Quelle est la meilleure façon de retourner un tuple de la fonction en C++11?

Je veux retourner certaines valeurs d'une fonction et je veux l'emballer dans un tuple. J'ai donc deux possibilités de déclaration de fonction:

std::tuple<bool, string, int> f()
{
  ...
  return std::make_tuple(false, "home", 0);
}

Et

std::tuple<bool, string, int> f()
{
  ...
  return std::forward_as_tuple(false, "home", 0);
}

Ces fonctions sont équivalentes? Entre ces fonctions Que préférez-vous?

22
demandé sur Andy Prowl 2013-05-23 15:54:26

2 réponses

std::forward_as_tuple() crée un tuple de références. Puisque vous renvoyez un tuple<bool, string, int> de toute façon, les deux finissent par être équivalents dans ce cas, mais je pense que la première approche est plus claire-utiliser forward_as_tuple() lorsque vous ne transmettez rien est source de confusion.

Aussi, comme mentionné par Sebastian Redl dans les commentaires, make_tuple() permettrait au compilateur d'effectuer une élision de copie - par paragraphe 12.8/31 de la norme C++11, alors que forward_tuple() ne le ferait pas (puisque ce qu'il retourne n'a pas le même type que le type de retour de la fonction).

19
répondu Andy Prowl 2013-05-23 12:03:07

Je préfère,

std::tuple<bool, std::string, int> f()
{
  ...
  return { false, "home", 0 };
}

Modifier 1

Le code ci-dessus est en train de compiler pour moi sous clang/libc++ trunk. Comme @ AndyProwl a commenté dans la section commentaires, cela ne devrait pas puisque le constructeur std:: tuple est explicite et le retour par la syntaxe initialization-list est dans le contexte copy-initialization, donc copy-list-initialization, qui échoue quand un constructeur explicite est apparié.

Je ne connais pas la raison pour laquelle clang / libc++ passe, je suppose que c'est un bug dans libc++. Quoi qu'il en soit, c'est triste de ne pas pouvoir faire ça pour les tuples...

Je pense que j'ai réalisé à quel point c'est triste (pour moi, enfin), en général. Je m'habituais à cette syntaxe, mais on est obligé de savoir à l'avance si le type de retour contient un constructeur explicite à tout moment pour que cela fonctionne.

Modifier 2

Ceci est en effet une extension libc++, pour plus d'informations, checkout Howard Hinnant réponse ici: https://stackoverflow.com/a/14963014 .

Il est également ouvert en la liste des bogues de libc++: http://llvm.org/bugs/show_bug.cgi?id=15299 .

C'est la proposition pertinente: Daniel Krügler, améliorer la paire et le tuple.

Bref, c'est ce qui se passe avec libc++:

#include <tuple>
#include <string>

struct S
{
    explicit S(int) {}
};

int main()
{
    std::tuple<int, std::string> t1 = { 1, "hello" }; // ok
    std::tuple<std::string> t2      = "hello";        // ok
    std::tuple<int, S> t3           = { 1, 1 };       // fail: an *element* is to be constructed explicitly
}
5
répondu pepper_chico 2017-05-23 12:34:30