web-dev-qa-db-ja.com

`std :: make_Tuple`の理由は何ですか?

なぜstd::make_Tuple存在しますか?テンプレートパラメータを回避できるため、関数が入力する必要のある文字の量を削減する状況があることを知っています。しかし、それが唯一の理由ですか?何がstd::Tuple他のクラステンプレートにそのような関数がないのに、関数が存在することは特別ですか? std::Tupleそのような状況でより頻繁に?


std::make_Tupleは文字数を減らします:

// Avoiding template parameters in definition of variable.
// Consider that template parameters can be very long sometimes.
std::Tuple<int, double> t(0, 0.0); // without std::make_Tuple
auto t = std::make_Tuple(0, 0.0);  // with std::make_Tuple

// Avoiding template parameters at construction.
f(std::Tuple<int, double>(0, 0.0)); // without std::make_Tuple
f(std::make_Tuple(0, 0.0));         // with std::make_Tuple

しかし、上記のように、他の多くのクラステンプレートには、このような関数はありません。

26
JojOatXGME

コンストラクタで引数の控除を使用できないからです。明示的にstd::Tuple<int, double>(i,d);を記述する必要があります。

タプルを作成してワンショットで別の関数に渡すのに便利です。

takes_Tuple(make_Tuple(i,d)) vs takes_Tuple(tuple<int,double>(i,d))

iまたはdのタイプが変更されると、特に古いタイプと新しいタイプの間で変換が発生する可能性がある場合に、変更する場所が1つ少なくなります。

std::Tuple(i,d);を記述できた場合、_make_*_は(おそらく)冗長になります。

(ここで理由を尋ねないでください。構文A a();がデフォルトのコンストラクターを呼び出さないのと同様の理由が原因かもしれません。C++構文の特異な問題がいくつかあります。)

UPDATE注:Daniel が正しく気付くように、c ++ 17が拡張され、テンプレート引数の推定がコンストラクターで機能するようになります、そのような委任は廃止されます。

25
luk32

提案でmake_Tupleとその他のさまざまなmake_ *ユーティリティが必要な理由の根拠を見つけることができます N3602:コンストラクターのテンプレートパラメーターの控除 これは(emphasis mine):

このペーパーでは、関数のテンプレートパラメーター演繹をテンプレートクラスのコンストラクターに拡張することを提案します。問題と解決策を説明する最も明確な方法は、いくつかの例です。

次のように定義したとします。

vector<int> vi1 = { 0, 1, 1, 2, 3, 5, 8 }; 
vector<int> vi2; template<class Func> 
    class Foo() { 
        public: Foo(Func f) : func(f) {} 
        void operator()(int i) { os << "Calling with " << i << endl; f(i); } 
        private: 
        Func func;
    };

現在、テンプレートクラスをインスタンス化する場合は、テンプレートパラメータを指定するか、「make_ *」ラッパーを使用し、関数のテンプレートパラメータの推論を利用する必要があります、または完全にパント:

pair<int, double> p(2, 4.5); 
auto t = make_Tuple(4, 3, 2.5); 
copy_n(vi1, 3, back_inserter(vi2)); // Virtually impossible to pass a lambda to a template class' constructor
for_each(vi.begin(), vi.end(), Foo<???>([&](int i) { ...}));

注:この提案は EWG issue 6 で追跡されています。

8
Shafik Yaghmour

テンプレート引数の控除のみ。ただし、これはラムダを使用するために必要な(考案された)例です。

_class A
{
public:
    template<typename F>
    A(const std::Tuple<F> &t)
    {
        // e.g.
        std::get<0>(t)();
    }
};

class B : public A
{
public:
     B(int i) : A(std::make_Tuple([&i]{ ++i; }))
     {
         // Do something with i
     }
};
_

2つのラムダ式の型が異なるため、std::Tuple<decltype([&i]{ ++i; })>([&i]{ ++i; })は使用できません。 _std::function_のようなポリモーフィックラッパーは、ランタイムオーバーヘッドを追加します。ユーザー定義のoperator ()を持つ名前付きクラスが機能します(演算子の本体の内容によっては、Bのフレンドである必要がある場合もあります)。これは、C++ 11より前の昔に使用したものです。

1
Arne Vogel

そのような関数の賢い使い方はパラメーターとして渡されることだと思います。
そんな感じ:

std::bind_front(&std::make_Tuple, 1, "test", true);

私が間違っていなければ、コンストラクタを直接呼び出すことができないので、それは役に立つかもしれません。

auto obj = Object::Object(3); // error: cannot call constructor ‘Object::Object’ directly [-fpermissive]
1
David Gallay