2012-07-05 83 views
8

我有下面的代码片段,虽然完全无关紧要,但它说明了我试图在更一般的代码中使用的模式。用lambda和std :: function的C++ 11类型推理

template<typename InT, typename ResT> 
ResT unary_apply(InT val, std::function<ResT(InT)> fn) 
{ 
    return fn(val); 
} 

我希望能够与函数指针,仿函数,lambda表达式等unary_apply拨打:因此使用的std::function抽象一切都抛弃。

当我尝试使用上述以下列方式,C++(G ++ 4.7)无法执行相关类型推断:

double blah = unary_apply(2, [](int v) { return 3.0 * v; }); 

src/fun.cpp:147:75: error: no matching function for call to ‘unary_apply(int, test()::<lambda(int)>)’ 
src/fun.cpp:147:75: note: candidate is: 
src/fun.cpp:137:6: note: template<class InT, class ResT> ResT unary_apply(InT, std::function<ResT(InT)>) 
src/fun.cpp:137:6: note: template argument deduction/substitution failed: 
src/fun.cpp:147:75: note: ‘test()::<lambda(int)>’ is not derived from ‘std::function<ResT(double)>’ 

失败,我发现,我必须明确指定模板参数(实际上我相信它只是返回类型是无法推断的):

double blah = unary_apply<int, double>(2, [](int v) { return 3.0 * v; }); 

我对C++ 11中的类型推断规则并不熟悉,但上面的行为似乎是合理的(我可以看到,通过std::function的内部机制推断可能是一个很大的问题)。我的问题是:是否有可能重写上面的函数以保持相同的灵活性(就可以作为第二个参数传递的函数/函子等类型而言),同时还提供了更多类型推断的线索所以我不必在调用点明确提供模板参数?

回答

9

去有点鸭键入y应该工作:

template <typename T, typename F> 
auto unary_apply(T&& val, F&& func) -> decltype(func(val)) { 
    return func(std::forward<T>(val)); 
} 
+0

提出的解决方案是正确的,第一句话是没有的。类型推断不能在问题中应用的原因与它是lambda的事实无关(您可以通过任何其他函子/函数,但仍然无法推断该类型) – 2012-07-05 12:24:12

+0

@DavidRodríguez-dribeas:再次阅读。 Lambda不是*函数*类型。这是一个带有'operator()'的无名类类型。但是,是的,用'std :: function '这个推论可能不会起作用。 – 2012-07-05 12:25:02

+0

我错过了那部分,纠正了注释:问题不是它是lambda,而是'std :: function'的模板参数处于不可诱导的上下文中,尝试传递一个常规函数(而不是'std :: function < >' - 或者你的意思是* lambda不是一个'std :: function'实例化?) – 2012-07-05 12:27:29