使用std :: function

时间:2016-08-26 19:30:40

标签: 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 _ + 2;});
    stdfunc_test(test_func);
}

main中的两行都会导致错误:

  

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

尝试在Visual Studio 2015中编译时。

为什么类型扣除不会从函数类型中扣除模板类型,是否有解决方法?

2 个答案:

答案 0 :(得分:2)

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

#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;
}

你可以在这里试一试:http://fiddle.jyt.io/github/d4ab355eb2ab7fc4cc0a48da261f0127

答案 1 :(得分:1)

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

  

通常,推导过程会尝试查找模板参数值,这些参数值将使推导出的A与A相同(在如上所述转换类型A之后)。但是,有三种情况可以产生差异:

     
      
  • 如果原始P是引用类型,则推导出的A(即引用所引用的类型)可以比转换后的A更符合cv。
  •   
  • 转换后的A可以是另一个指向成员类型的指针或指针,可以通过函数指针转换([conv.fctptr])和/或限定转换([conv.qual])将其转换为推导出的A. LI>   
  • 如果P是一个类而P的形式为simple-template-id,那么转换后的A可以是推导出的A的派生类。同样,如果P是指向一个类的形式simple-template-的指针id,转换后的A可以是指向推导出的A所指向的派生类的指针。
  •   

但是,如果模板参数没有参与模板参数推断,则将执行隐式转换:(temp.arg.explicit

  

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

因此,如果您明确指定模板参数,它应该可以工作:

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