将lambda作为模板函数参数传递

eml*_*lai 17 c++ lambda templates c++11

为什么以下代码没有编译(在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; });
}
Run Code Online (Sandbox Code Playgroud)

错误消息是:

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&)) { }
     ^
Run Code Online (Sandbox Code Playgroud)

但它并不能解释为什么它与参数不匹配.

如果我做qux一个非模板函数,替换FromTToint,它编译.

sky*_*ack 12

lambda函数不是正常函数.每个lambda都有自己的类型, To (&)(const From&)在任何情况下都不是.在您的情况下,
非捕获lambda可以To (*)(const From&)使用以下方法衰减:

qux(ts, +[](const T&) { return 42; });
Run Code Online (Sandbox Code Playgroud)

正如评论中所指出的,从lambda中获取它的最佳方法是:

#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() {}
Run Code Online (Sandbox Code Playgroud)

注意:我认为推断返回类型和参数类型对于实际问题是必需的.否则,您可以轻松地将整个lambda推断为通用可调用对象并直接使用它,无需任何衰减.

  • 实际上,只有`*`就足够了,不需要`*+`. (2认同)

eml*_*lai 10

如果您不需要使用推导To类型,则可以推断出整个参数的类型:

template<typename From, typename F>
void qux(const std::vector<From>&, const F&) { }
Run Code Online (Sandbox Code Playgroud)

  • `的std :: result_of` (3认同)
  • @DanielJour 这有一个不幸的副作用,即必须使用 `std::result_of&lt;[…]&gt;::type` 去模板元编程忍者以获得我需要的 `F` 的返回类型(我不知道如何做模板魔术来获得它)。另请注意,`*+` 不是必需的,`*` 就足够了。 (2认同)

Edg*_*jān 6

如果我错了,请纠正我,但模板参数推导仅推导出确切的类型而不考虑可能的转换.

因此编译器不能推断ToFromTo (&)(const From&)因为qux预计到函数的引用,但您提供有它自己的lambda.