我仍然在努力学习一些C++语法。
这一次,我想用lambda添加额外的参数。但是为了使代码泛型,我希望能够接受任何函数及其参数:
#include <functional>
#include <exception>
template<typename R>
class Nisse
{
private:
Nisse(Nisse const&) = delete;
Nisse(Nisse&&) = delete;
Nisse& operator=(Nisse const&) = delete;
Nisse& operator=(Nisse&&) = delete;
public:
//Nisse(std::function<R()> const& func) {} // disable for testing
template<typename... Args>
Nisse(std::function<R(Args...)> const& func, Args... a) {}
};
int main()
{
// I was hoping this would deduce the template arguments.
Nisse<int> nisse([](int a,double d){return 5;},12,12.0);
}这将生成:
> g++ -std=c++0x Test.cpp
Test.cpp:21:61: error: no matching function for call to ‘Nisse<int>::Nisse(main()::<lambda(int, double)>, int, double)’
Test.cpp:21:61: note: candidate is:
Test.cpp:16:9: note: template<class ... Args> Nisse::Nisse(const std::function<R(Args ...)>&, Args ...)我尝试显式指定模板类型:
Nisse<int> nisse<int,double>([](int a,double d){return 5;},12,12.0);但这(令我惊讶的)是一个语法错误:
> g++ -std=c++0x Test.cpp
Test.cpp: In function ‘int main()’:
Test.cpp:21:23: error: expected initializer before ‘<’ token
Test.cpp:21:65: error: expected primary-expression before ‘,’ token
Test.cpp:21:73: error: expected ‘;’ before ‘)’ token发布于 2013-02-15 02:00:57
你不能从一个lambda中推断出std::function模板参数。接受任意可调用的通常方式是通过通用引用:
template<typename F, typename... Args,
typename = typename std::enable_if<std::is_convertible<
decltype(std::declval<F>()(std::declval<Args>()...)), R>::value>::type>
Nisse(F &&f, Args... a): Nisse(std::function<R()>(std::bind(f, a...))) {}最后一个(匿名的,默认的)模板参数在这里用于验证第一个模板参数是否为类似函数,并返回R类型的结果。
std::enable_if<std::is_convertible<
decltype(std::declval<F>()(std::declval<Args>()...)), R>::value>::type正如@Yakk在下面的注释中所描述的,上面的表达式检查F是否是一个结果为R的函数类型。如果它可以工作,那么一切都很好。如果失败,则会生成一个编译时错误(注意:这里使用SFINAE)。
对于方法,SFINAE被插入到返回类型中,但对于构造函数,这不是一个选项;以前添加了额外的默认构造函数参数,但添加默认模板参数更优雅,因为它根本不会更改构造函数签名。匿名模板参数的SFINAE在可变模板参数之后特别有吸引力,因为用户没有办法(意外地?)覆盖默认值。
https://stackoverflow.com/questions/14880934
复制相似问题