如何使用lambda作为第一个参数覆盖可变参数模板?

smi*_*lar 1 c++ lambda variadic-templates c++11

为什么以下函数覆盖(lambda作为第一个参数)不起作用?

template<typename ...Args>
void call(Args&& ...args) {
    std::cout << "call 1";
}

template<typename ...Args>
void call(CustomObject object, Args&& ...args) {
    std::cout << "call 2";
}

// see this function
template<typename ...Args>
void call(std::function<void ()>, Args&& ...args) {
    std::cout << "call 3";
}
Run Code Online (Sandbox Code Playgroud)
  • call()输出'调用1'
  • call(CustomObject())输出'调用2'
  • call([](){})输出'调用1' // 错误

为什么不call([](){})输出'call 3'

我应该如何声明call([](){})输出'call 3'的函数?

编辑: @KennyTM给出了上述答案.

template<typename F, typename ...Args>
auto call(F&& f, Args&& ...args)
    -> typename std::enable_if<std::is_same<decltype(f()), void>::value>::type
{
    std::cout << "call 3\n";
}
Run Code Online (Sandbox Code Playgroud)

但是......如果lambda有参数怎么办?像这样:

class CustomObject {};

template<typename ...Args>
void call(std::function<void (CustomObject *)>, Args&& ...args) {
    std::cout << "call 4";
}
Run Code Online (Sandbox Code Playgroud)

如何让call([](CustomObject *){})输出'调用4'

编辑: @ildjarn给出了答案:

template<typename F, typename ...Args>
auto call(F&& f, Args&& ...)
    -> typename std::enable_if<std::is_same<decltype(f( std::declval<CustomObject*>() )), void>::value>::type
{
    std::cout << "call 4\n";
}
Run Code Online (Sandbox Code Playgroud)

ken*_*ytm 6

lambda的类型是一个匿名类型,它有一个operator().它不是std::function<>.

您可以检查第一个参数是否为调用3的仿函数(演示:http://ideone.com/IQ4N6L),而不是专门化类型:

#include <iostream>
#include <type_traits>

template<typename F, typename ...Args>
auto call(F&& f, Args&& ...args)
    -> typename std::enable_if<std::is_same<decltype(f()), void>::value>::type
{
    std::cout << "call 3\n";
}


template<typename ...Args>
void call(Args&& ...args) {
    std::cout << "call 1\n";
}



int main() {
    call(1);
    call([](){});
}
Run Code Online (Sandbox Code Playgroud)