web-dev-qa-db-ja.com

C ++ 11の関数からタプルを返す最良の方法は何ですか?

関数からいくつかの値を返し、それをタプルにパックしたいと思います。したがって、関数宣言には2つの可能性があります。

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

そして

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

これらの関数は同等ですか?これらの機能の間でどちらが好きですか?

25

std::forward_as_Tuple()参照のタプルを作成します。とにかく_Tuple<bool, string, int>_を返すので、2つは同等になりますこの場合ですが、最初のアプローチの方が明確だと思います-転送しないときにforward_as_Tuple()を使用します何でも混乱します。

また、コメントでSebastian Redlが述べているように、make_Tuple()は、コンパイラがコピーの省略を実行できるようにします-C++ 11標準の段落12.8/31に従って、forward_Tuple()は実行できません(返されるものは、関数の戻り値の型と同じ型ではありません)。

21
Andy Prowl

私は好きです、

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

編集1

上記のコードは、実際にはclang/libc ++トランクの下でコンパイルされています。 @AndyProwlがコメントセクションでコメントしたように、std :: Tupleコンストラクターは明示的であり、初期化リスト構文を介して返されるのはコピー初期化コンテキストであるため、これはすべきではありません。したがって、コピーリスト初期化は、明示的なコンストラクターが一致すると失敗します。

Clang/libc ++が渡される理由はわかりませんが、libc ++のバグだと思います。とにかく、タプルに対してそれができないのは悲しいことです...

一般的に、(私にとっては)それがどれほど悲しいかを実感したと思います。私はその構文に慣れてきましたが、返される型に明示的なコンストラクターが含まれているかどうかを事前に知る必要があります。

編集2

これは確かにlibc ++拡張機能です。詳細については、Howard Hinnantの回答をここで確認してください: https://stackoverflow.com/a/14963014

現在、libc ++のバグリストでも公開されています: http://llvm.org/bugs/show_bug.cgi?id=15299

これは関連する提案です: DanielKrügler、ペアとタプルの改善

要するに、これは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
}
6
pepper_chico