web-dev-qa-db-ja.com

make_unique / make_sharedを介してinitializer_listコンストラクターを呼び出す

私はstd::make_uniqueを使用して、コンストラクタがstd::initializer_listを受け取るクラスをインスタンス化しようとしています。ここでは最小限のケース:

#include <string>
#include <vector>
#include <initializer_list>
#include <memory>

struct Foo {
    Foo(std::initializer_list<std::string> strings) : strings(strings) {}

    std::vector<std::string> strings;
};

int main(int, char**) {

    auto ptr = std::make_unique<Foo>({"Hello", "World"});

    return 0;
}

Colir でビルドできないことがわかります:

main.cpp:14:56: error: no matching function for call to 'make_unique(<brace-enclosed initializer list>)'
     auto ptr = std::make_unique<Foo>({"Hello", "World"});

では、make_uniqueinitializer_listsを使用できないと報告されていますか? GCC 4.9.1にバグはありますか?または私は何かを見落としましたか?

29
Quentin

_std::make_unique_は、オブジェクトコンストラクターに渡される引数の型を推定する関数テンプレートです。残念ながら、括弧で囲まれたリストは(auto宣言を除いて)推定できません。そのため、不足しているパラメーターの型の場合、関数テンプレートをインスタンス化できません。

_std::make_unique_を使用することはできませんが、そのルートは使用しないでください。子供のために、可能な限りネイキッドnewsを使用しないでください。または、型を指定して型の推論を機能させることができます。

  • std::make_unique<Foo>(std::initializer_list<std::string>({"Hello", "World"}))

  • std::make_unique<Foo, std::initializer_list<std::string>>({"Hello", "World"})

  • auto il = { "Hello"s, "World"s }; auto ptr = std::make_unique<Foo>(il);

最後のオプションはauto宣言に特別なルールを使用します。これは(上記で示唆したように)do実際に_std::initializer_list_を導き出します。

33
Kerrek SB

いくつか追加の文字を入力する準備ができている場合は、これを行うことができます。

auto ptr = std::make_unique<Foo>( make_init_list( { "Hello"s , "World"s } ));

ここで、init_listは次のように定義されています

template<typename T>
std:: initializer_list<T> make_init_list ( std:: initializer_list<T> && l ) {
    return l;
}

これにより、控除を行うことができ、これを行う必要のあるコードに多くの場所がある場合に便利です。

(clang 3.9とgcc 6.2.0で動作します。std::string- literalを微調整してmake_sharedに変更する必要があったことを除いて、g ++-4.8.4でも動作するようになりました。ただし、 make_init_list内のTは問題なく動作しました。)

実際、これは拡張機能ですか? make_init_listの控除の成功は、規格で要求されているかどうか?

4
Aaron McDaid