为什么下面的代码没有编译(在C ++ 11模式下)?
#include <vector>
template<typename From, typename To>
void qux(const std::vector<From>&, To (&)(const From&)) { }
struct T { };
void foo(const std::vector<T>& ts) {
qux(ts, [](const T&) { return 42; });
}
错误消息是:
prog.cc:9:5: error: no matching function for call to 'qux'
qux(ts, [](const T&) { return 42; });
^~~
prog.cc:4:6: note: candidate template ignored: could not match 'To (const From &)' against '(lambda at prog.cc:9:13)'
void qux(const std::vector<From>&, To (&)(const From&)) { }
^
但它没有解释为什么它与参数不匹配。
如果我将qux
作为非模板函数,将From
替换为T
,将To
替换为int
,则会进行编译。
答案 0 :(得分:13)
lambda函数不是正常函数。在任何情况下,每个lambda都有自己的类型 To (*)(const From&)
在您的情况下,非捕获lambda可以使用:
qux(ts, +[](const T&) { return 42; });
#include <vector>
template<typename From, typename To>
void qux(const std::vector<From>&, To (&)(const From&)) { }
struct T { };
void foo(const std::vector<T>& ts) {
qux(ts, *+[](const T&) { return 42; });
}
int main() {}
如评论中所述,你可以做的最好的事情是从lambda中取出它:
aBytes = b'\x00\x47\x40\x00\x13\x00\x00\xb0'
print (aBytes)
print (''.join ([hex (aByte) for aByte in aBytes]))
注意:我认为推断返回类型和参数类型对于实际问题是必需的。否则你可以很容易地将整个lambda推断为通用的可调用对象并直接使用它,不需要腐烂任何东西。
答案 1 :(得分:10)
如果您不需要使用推导的To
类型,则可以推断出整个参数的类型:
template<typename From, typename F>
void qux(const std::vector<From>&, const F&) { }
答案 2 :(得分:6)
如果我错了,请纠正我,但模板参数扣除仅推断出确切的类型而不考虑可能的转换。
因此,编译器无法为To
推导出From
和To (&)(const From&)
,因为qux
需要对函数的引用,但是您提供了一个具有自己类型的lambda。
答案 3 :(得分:2)
你绝对没有机会编译猜测To
是什么。因此,您需要明确指定它。
此外,lambda需要通过指针传递。
最后,这个版本编译好了:
template<typename From, typename To>
void qux(const std::vector<From>&, To (*)(const From&)) { }
struct T { };
void foo(const std::vector<T>& ts) {
qux<T,int>(ts,[](const T&) { return 42; });
}
答案 4 :(得分:2)
您期望两种隐式类型转换(从未命名的函数对象类型到函数引用类型)和模板类型推导都会发生。但是,you can't have both,因为您需要知道目标类型以找到合适的转换序列。
答案 5 :(得分:1)
但它没有解释为什么它与参数不匹配。
模板推导尝试完全匹配类型。如果无法推断出类型,则扣除失败。从不考虑转换。
在这个表达式中:
qux(ts, [](const T&) { return 42; });
lambda表达式的类型是一些唯一,未命名类型。无论那种类型是什么,它绝对不是To(const From&)
- 因此扣除失败。
如果我将
qux
作为非模板函数,将From
替换为T
,将To
替换为int
,则会进行编译。
事实并非如此。但是,如果参数是指针而不是引用来运行,那么它就是。这是因为没有捕获的lambda可以隐式转换为等效的函数指针类型。允许在演绎的范围之外进行此转换。
template <class From, class To>
void func_tmpl(From(*)(To) ) { }
void func_normal(int(*)(int ) ) { }
func_tmpl([](int i){return i; }); // error
func_tmpl(+[](int i){return i; }); // ok, we force the conversion ourselves,
// the type of this expression can be deduced
func_normal([](int i){return i; }); // ok, implicit conversion
这就是失败的原因:
template <class T> void foo(std::function<T()> );
foo([]{ return 42; }); // error, this lambda is NOT a function<T()>
但这成功了:
void bar(std::function<int()> );
bar([]{ return 42; }); // ok, this lambda is convertible to function<int()>
首选方法是推断出可调用类型,并使用std::result_of
选择结果:
template <class From,
class F&&,
class To = std::result_of_t<F&&(From const&)>>
void qux(std::vector<From> const&, F&& );
现在你可以正常传递你的lambda,函数或函数对象。