2017-07-02 55 views
1

我该如何最好地定义模板函数applyFunc来匹配lambda的签名?模板与std ::函数不直接匹配lambda

我不想定义一个通用模板参数捕捉功能型作为一个整体, 因为我想用的类型E传入的函数的自变量的。

#include <functional> 
template<class E> 
int applyFunc(std::function<int(E)> f) { 
    return f(E{}); 
} 

int main() 
{ 
    auto asLambda = [](int d) -> int { return d+d; }; 
    std::function<int(int)> asFunc = asLambda; 

    applyFunc(asLambda); //this doesn't :(
    applyFunc(asFunc); //this works 
} 

编译失败:

15:23: error: no matching function for call to 'applyFunc(main()::<lambda(int)>&)' 
15:23: note: candidate is: 
6:5: note: template<class E> int applyFunc(std::function<int(E)>) 
6:5: note: template argument deduction/substitution failed: 
15:23: note: 'main()::<lambda(int)>' is not derived from 'std::function<int(E)>' 
+0

'applyFunc ([](INT d){返回d + d;})' – cpplearner

+4

用户定义的转换不模板参数推导过程中考虑。所以'E'不能推导出来,除非参数的类型是'std :: function ';仅仅可以转换成这种类型是不够的。您可以通过@cpplearner显示,明确指定'E'。 –

+2

查看相关列表......“重载std :: function参数以匹配lambda”,“lambda的模板参数演绎”等。_all_回答你的问题,不是? – ildjarn

回答

1

我怎样才能最好的定义模板功能applyFunc匹配拉姆达的签名?

只要您接受只使用非捕获lambda表达式(就像您在示例代码中所做的那样),就可以利用它们衰减到函数指针的事实。
作为最小的,工作示例:

template<class E> 
int applyFunc(int(*f)(E)) { 
    return f(E{}); 
} 

int main() { 
    auto asLambda = [](int d) -> int { return d+d; }; 
    applyFunc(+asLambda); 
} 

如果你想使用捕捉lambda表达式来代替,你可以提取类型E不知何故,如果你接受如下:

  • 你必须使用一个通用的类型F代替std::function
  • 不能使用通用的Lambda表达式

然后,你可以直接看看你的lambda的operator()
它遵循最小,工作示例:

template<typename F> 
struct GetFrom { 
    template<typename R, typename E> 
    static E typeE(R(F::*)(E) const); 

    // required for mutable lambdas 
    template<typename R, typename E> 
    static E typeE(R(F::*)(E)); 
}; 

template<class F> 
int applyFunc(F f) { 
    using E = decltype(GetFrom<F>::typeE(&F::operator())); 
    return f(E{}); 
} 

int main() { 
    int i = 0; 
    applyFunc([i](int d) mutable -> int { return d+d; }); 
    applyFunc([i](int d) -> int { return d+d; }); 
} 

你可以很容易地扩展到多个参数,如果你需要。使用std::tuple作为返回类型,并从中获取第i个类型。

最后,如果你想使用捕捉lambda表达式并将它们分配到一个std::function无论出于何种原因,要知道,E不能自动推断,因此必须显式地指定它(由@在评论的问题建议cpplearner):

applyFunc<int>([](int d) { return d+d; }) 

EDIT

GetFrom也可以在SFINAE表达式直接使用,作为热曲在评论中提到。
作为最小的,工作示例:

#include<type_traits> 

template<typename F> 
struct GetFrom { 
    template<typename R, typename E> 
    static E typeE(R(F::*)(E) const); 

    // required for mutable lambdas 
    template<typename R, typename E> 
    static E typeE(R(F::*)(E)); 
}; 

template<class F, typename E = decltype(GetFrom<F>::typeE(&F::operator()))> 
std::enable_if_t<std::is_same<E, int>::value, E> 
applyFunc(F f) { 
    return f(E{}); 
} 

template<class F, typename E = decltype(GetFrom<F>::typeE(&F::operator()))> 
std::enable_if_t<std::is_same<E, double>::value, E> 
applyFunc(F f) { 
    return f(E{}); 
} 

int main() { 
    int i = 0; 
    applyFunc([i](int d) mutable -> int { return d+d; }); 
    applyFunc([i](double d) -> int { return d+d; }); 
    // this won't compile, as expected 
    // applyFunc([i](char d) -> int { return d+d; }); 
} 
+0

我可以扩展GetFrom,使我可以启用/禁用applyFunc变体与enable_if? – JE42

+1

@ JE42编辑答案。请让我知道这对你有没有用。 – skypjack