如果模板没有可变参数,则将Lambda推导为std :: function

pon*_*ong 12 c++ c++11 visual-c++-2015

template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}

template<typename ReturnT, typename ParamT>
void bar(std::function<ReturnT(ParamT)> callback)
{}

main()
{    
    foo<int, int>([](int x){ return x; });  // no instance of function 
                                            //   template matches argument list
    bar<int, int>([](int x){ return x; });  // OK
}
Run Code Online (Sandbox Code Playgroud)

foobar之间的唯一区别是foo具有可变参数.不知何故,编译器能够将lambda转换为bar中的std :: function .

据我所知,模板类型推导不考虑类型转换.那么两个都不应该失败吗?

Cal*_*eth 10

您没有任何类型参数的扣除bar,它们是完全指定的.

你仍然有包的尾部推断foo,并且失败因为lambda不是std::function.

  • 据推测,当试图找到适当的std :: function构造函数时,参数类型转换中对bar的调用会发生一些类型推导.只是不直接找到合适的酒吧. (2认同)

Yak*_*ont 6

template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}
Run Code Online (Sandbox Code Playgroud)

现在,foo<int,int>foo<ReturnT=int, ParamsT starts with {int}>.

它没有完全说明ParamT.实际上,没有办法完全指定ParamT.

作为未完全指定的模板,演绎发生并失败.它不会尝试"如果我只是假设包装不再进一步".

你可以解决这个问题:

template<typename ReturnT, typename... ParamT>
void foo(block_deduction<std::function<ReturnT(ParamT...)>> callback)
{}
Run Code Online (Sandbox Code Playgroud)

其中block_deduction的样子:

template<class T>
struct block_deduction_helper { using type=T; }:
template<class T>
using block_deduction = typename block_deduction_helper<T>::type;
Run Code Online (Sandbox Code Playgroud)

现在扣除在foo第一个参数上被阻止了.

你的代码有效.

当然,如果你传入std::function它将不再自动推断参数.

请注意,推断类型擦除类型的类型std::function通常是代码味道.

将两者替换为:

template<class F>
void bar(F callback)
{}
Run Code Online (Sandbox Code Playgroud)

如果你必须获得参数,请使用函数特性助手(SO上有很多).如果你只需要返回值,那么有些std特征已经可以解决了.


您可以这样做:

tempate<class R, class...Args>
void bar( std::function<R(Args...)> f ) {}
template<class F>
void bar( F f ) {
  std::function std_f = std::move(f);
  bar(std_f);
}
Run Code Online (Sandbox Code Playgroud)

使用演绎指南功能.