12
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
}

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

据我了解,模板类型推导不考虑类型转换。所以不应该都失败吗?

4

2 回答 2

10

您对 的类型参数没有任何推论bar,它们是完全指定的。

您仍然需要推断出包尾,但foo由于 lambda 不是std::function.

于 2018-10-17T08:26:23.507 回答
6
template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}

现在,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)
{}

block_deduction看起来像:

template<class T>
struct block_deduction_helper { using type=T; }:
template<class T>
using block_deduction = typename block_deduction_helper<T>::type;

现在推论在foo的第一个参数上被阻止了。

你的代码有效。

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

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

将两者都替换为:

template<class F>
void bar(F callback)
{}

如果您必须获取参数,请使用函数特征助手(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);
}

使用演绎指南功能。

于 2018-10-17T13:49:39.057 回答