3

C++11 では、ラムダ関数はオブジェクトであり、それで make_tuple を呼び出すことができるはずですよね?

void foobar() {
    auto t = std::make_tuple([](){ std::make_shared<int>(); });
}

このコードは私にとってはうまくいきます。

可変個引数テンプレートを追加するとどうなるか:

#include <tuple>
#include <memory>

template <class... T>
void foobar() {
    auto t = std::make_tuple([](){ std::make_shared<T>(); }...);
}

int main(int, char**)
{
    foobar<int, float, double>();
    return 0;
}

これは GCC 4.7.2 でコンパイルに失敗します

main.cpp: In lambda function:
main.cpp:6:54: error: parameter packs not expanded with '...':
main.cpp:6:54: note:         'T'
main.cpp: In function 'void foobar()':
main.cpp:6:57: error: expansion pattern '#'lambda_expr' not supported by dump_expr#<expression error>' contains no argument packs
main.cpp: In instantiation of 'void foobar() [with T = {int, float, double}]':
main.cpp:11:29:   required from here

このコードは標準で正しいのでしょうか?

4

2 に答える 2

6

これは gcc の既知のバグです: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41933 (最初の例は、パラメーター パックのキャプチャをカバーする別のパターンですが、その根底にある問題とマージされたバグgcc は単にラムダと変数の共通部分を実装していないということです)。

標準に関する限り、これは完全に受け入れられるコードです。

于 2012-11-20T09:23:26.907 に答える
4

アプローチ #1:

それを回避する簡単な方法は次のようですstd::function

#include <tuple>
#include <memory>

template <class T>
std::function<std::shared_ptr<T>()> make_shared_lambda() {
    return [](){ return std::make_shared<T>(); };
}

template <class... T>
void foobar() {
    auto factories = std::make_tuple(make_shared_lambda<T>()...); 
    auto tracer = std::get<2>(factories)();
}

// demonstration 
#include <cstdio>
struct Tracer { 
    Tracer() { puts("Tracer()");   }
   ~Tracer() { puts("~Tracer()");  } 
};

int main()
{
    foobar<int, float, Tracer>();
}

版画

Tracer()
~Tracer()

アプローチ #2:

std::functionの型消去には明らかにパフォーマンスのオーバーヘッドがあります。ステートレス ラムダが関数ポインターに変換できるという事実を簡単に利用できます(標準 5.1.2/6)。

#include <tuple>
#include <memory>

template <class T> auto make_shared_f() -> std::shared_ptr<T>(*)() 
{
    return []() { return std::make_shared<T>(); };
}

template <class... T> std::tuple<std::shared_ptr<T>(*)()...> foobar() {
    return std::make_tuple(make_shared_f<T>()...);
}

// demonstration 
int main()
{
    auto factories = foobar<int, float, double>();
    auto double_ptr = std::get<2>(factories)();
}

コンパイラがテンプレート エイリアスをサポートしている場合は、少し暗号化を減らすことができます。

template <typename T> using shared_factory = std::shared_ptr<T>(*)();

template <class T> shared_factory<T> make_shared_f() {
    return []() { return std::make_shared<T>(); };
}
于 2012-11-20T09:22:35.510 に答える