web-dev-qa-db-ja.com

C ++ 1zでのstd :: make_pairとstd :: make_Tupleの有用性

私の理解では、 std::make_pairstd::make_Tuple が存在する唯一の理由は、型が自動的に推定されるため、自分で型を記述する必要がないためです。 C++ 1zでは、 クラステンプレートのテンプレート引数の推定 があります。これにより、簡単に記述できます。

std::pair p(1, 2.5); // C++1z

の代わりに

auto p = std::make_pair(1, 2.5); // C++11/14

std::Tuple の状況は類似しています。これにより、次の質問が発生します。C++ 1zでは、std::make_pairおよびstd::make_Tupleのコンストラクターを使用する代わりに、std::pairおよびstd::Tupleを使用することが有益な状況がありますか?

純粋なC++ 1zコード(つまり、C++ 14との下位互換性は不要)を検討し、誰もがこのC++ 1z機能に精通していると想定してください。

21
s3rvac

C++ 1zでは、_std::make_pair_と_std::make_Tuple_のコンストラクターを使用する代わりに、_std::pair_と_std::Tuple_を使用することが有益な状況はありますか?

すべてのルールには常に楽しい例外があります。 _std::reference_wrapper_に何をしたいですか?

_int i = 42;
auto r = std::ref(i);

pair p(i, r);                 // std::pair<int, std::reference_wrapper<int> >
auto q = std::make_pair(i,r); // std::pair<int, int&>
_

後者が必要な場合は、_std::make_pair_が必要です。


別の状況はジェネリックコードで発生しました。タプルに変換したいテンプレートパラメータパックがあるとしましょう。これを記述しますか?

_template <typename... Ts>
auto foo(Ts... ts) {
    return std::Tuple(ts...);
}
_

今、そのコードの意図はおそらくそれから_std::Tuple<Ts...>_を取得することですが、それは必然的に何が起こるかではありません。 _Ts..._に依存します:

  • _Ts..._がそれ自体がTupleである単一のオブジェクトである場合、そのコピーを取得します。つまり、foo(std::Tuple{1})は、_Tuple<int>_ではなく_Tuple<Tuple<int>>_を返します。
  • _Ts..._がpairである単一のオブジェクトである場合、それらの要素のTupleを取得します。つまり、foo(std::pair{1, 2})は、_Tuple<int, int>_ではなく_Tuple<pair<int, int>>_を返します。

ジェネリックコードでは、TupleのようなタイプにCTADを使用することは避けます。これは、何を取得するかが明確にならないためです。 _make_Tuple_にはこの問題はありません。 make_Tuple(tuple{1})は_Tuple<Tuple<int>>_であり、make_Tuple(pair{1, 2})は_Tuple<pair<int, int>>_です。


さらに、_std::make_pair_は関数テンプレートであるため、何かを実行したい別の関数テンプレートにそれを渡すことができます。

_foo(std::make_pair<int, int>);
_

これはあまり便利ではないようですが、誰かが問題を解決するためにそれを使用しています-そしてあなたはそこに_std::pair_を渡すことはできません。

31
Barry