在变量模板中使用lambdas调用std :: make_tuple - 这应该适用于C ++ 11吗?

时间:2012-11-20 09:12:03

标签: c++ c++11 tuples variadic-templates lambda

在C ++ 11中,lambda函数是一个对象,应该可以用它调用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

我想知道,这个代码是否符合标准?

2 个答案:

答案 0 :(得分:6)

这是gcc中的一个已知错误:http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41933(最初的示例是一个不同的模式,涵盖参数包的捕获,但问题的基础和合并的错误是gcc根本没有实现的交集lambdas和variadics)。

就标准而言,它是完全可以接受的代码。

答案 1 :(得分: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的类型擦除存在性能开销。您可以轻松利用stateless lambdas are convertible to function pointers(标准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>(); };
}