C++ 使用std::函数进行模板类型推断

C++ 使用std::函数进行模板类型推断,c++,templates,c++11,std-function,C++,Templates,C++11,Std Function,我在std::function和类型推断中发现了以下行为,这对我来说是意外的: #include <functional> template <typename T> void stdfunc_test(std::function<T(T)> func) {}; int test_func(int arg) { return arg + 2; } int main() { stdfunc_test([](int _) {return _

我在
std::function
和类型推断中发现了以下行为,这对我来说是意外的:

#include <functional>

template <typename T>
void stdfunc_test(std::function<T(T)> func) {};

int test_func(int arg)
{
    return arg + 2;
}

int main()
{
    stdfunc_test([](int _) {return _ + 2;});
    stdfunc_test(test_func);
}
#包括
模板
void stdfunc_测试(std::function func){};
int test_func(int arg)
{
返回arg+2;
}
int main()
{
stdfunc_测试([](int_){return_+2;});
stdfunc_测试(test_func);
}
main
中的两行都会导致错误:

没有函数模板“stdfunc_test”的实例与参数列表匹配

尝试在Visual Studio 2015中编译时


为什么类型推断不从函数类型中扣除模板类型,并且有解决方法吗?

在模板参数推断期间不执行隐式转换,除了:

一般来说,演绎过程试图找到模板参数值,使演绎的A与A相同(在类型A如上所述转换后)。但是,有三种情况允许存在差异:

  • 如果原始P是参考类型,则推导出的a(即参考引用的类型)比转换后的a更符合cv
  • 转换后的A可以是另一个指针或指向成员类型的指针,可以通过函数指针转换([conv.fctptr])和/或限定转换([conv.qual])转换为推导出的A
  • 如果P是一个类且P具有形式简单模板id,则转换后的a可以是推导出的a的派生类。同样,如果P是指向形式简单模板id的类的指针,则转换后的a可以是指向推导出的a所指向的派生类的指针
但是,如果模板参数不参与模板参数推导,则将执行隐式转换:()

如果参数类型不包含参与模板参数推导的模板参数,则将对函数参数执行隐式转换(子句[conv]),以将其转换为相应函数参数的类型。[注意:如果明确指定模板参数,则模板参数不参与模板参数推导

因此,如果显式指定模板参数,它应该可以工作:

stdfunc_test<int>([](int _) {return _ + 2;});
stdfunc_test<int>(test_func);
stdfunc_测试([](int){return 2;});
stdfunc_测试(test_func);

您可以使用模板推断函数和函子的签名:

#include<functional>

template<class T>
struct AsFunction
    : public AsFunction<decltype(&T::operator())>
{};

template<class ReturnType, class... Args>
struct AsFunction<ReturnType(Args...)> {
  using type = std::function<ReturnType(Args...)>;
};

template<class ReturnType, class... Args>
struct AsFunction<ReturnType(*)(Args...)> {
  using type = std::function<ReturnType(Args...)>;
};


template<class Class, class ReturnType, class... Args>
struct AsFunction<ReturnType(Class::*)(Args...) const> {
  using type = std::function<ReturnType(Args...)>;
};

template<class F>
auto toFunction( F f ) -> typename AsFunction<F>::type {
  return {f};
}

template <typename T>
void stdfunc_test(std::function<T(T)> func) {};

int test_func(int arg)
{
    return arg + 2;
}


int main()
{

    stdfunc_test( toFunction([](int _) {return _ + 2;}) );
    stdfunc_test( toFunction(test_func) );
    return 0;
}
#包括
模板
结构函数
:公共功能
{};
模板
结构函数{
使用type=std::function;
};
模板
结构函数{
使用type=std::function;
};
模板
结构函数{
使用type=std::function;
};
模板
auto-toFunction(F)->typename-AsFunction::type{
返回{f};
}
模板
void stdfunc_测试(std::function func){};
int test_func(int arg)
{
返回arg+2;
}
int main()
{
stdfunc_测试(toFunction([](int_){return_+2;}));
stdfunc_测试(toFunction(test_func));
返回0;
}

您可以在这里试用:

lambda和函数指针实际上都不是
std::function
-它们可以隐式转换为
std::function
。在推导模板变量时是否不考虑这种隐式转换?只需假设它是一个函数:
template void stdfunc\u test(T func)。然后用SimeAE限制模板的范围。不,模板参数推导不考虑用户定义的转换。即使它确实如此(尽管它不)-<代码> STD::函数< /C> >有一组模板化的构造函数,它们接受几乎任何东西,给予或接受。