std::function 模板类型推导
Template type deduction with 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
中的两行都导致错误:
no instance of function template "stdfunc_test" matches the argument list
在 Visual Studio 2015 年尝试编译时。
为什么类型推导不从函数类型中推导模板类型,有解决方法吗?
模板参数推导期间不执行隐式转换,除了:temp.deduct.call
In general, the deduction process attempts to find template argument values that will make the deduced A identical to A (after the type A is transformed as described above). However, there are three cases that allow a difference:
- If the original P is a reference type, the deduced A (i.e., the type referred to by the reference) can be more cv-qualified than the transformed A.
- The transformed A can be another pointer or pointer to member type that can be converted to the deduced A via a function pointer conversion ([conv.fctptr]) and/or qualification conversion ([conv.qual]).
- If P is a class and P has the form simple-template-id, then the transformed A can be a derived class of the deduced A. Likewise, if P is a pointer to a class of the form simple-template-id, the transformed A can be a pointer to a derived class pointed to by the deduced A.
但是,如果模板形参不参与模板实参推导,则会进行隐式转换:(temp.arg.explicit)
Implicit conversions (Clause [conv]) will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter type contains no template-parameters that participate in template argument deduction. [ Note: Template parameters do not participate in template argument deduction if they are explicitly specified.
因此,如果您显式指定模板参数,它应该可以工作:
stdfunc_test<int>([](int _) {return _ + 2;});
stdfunc_test<int>(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;
}
你可以在这里现场试用:http://fiddle.jyt.io/github/d4ab355eb2ab7fc4cc0a48da261f0127
我发现了 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
中的两行都导致错误:
no instance of function template "stdfunc_test" matches the argument list
在 Visual Studio 2015 年尝试编译时。
为什么类型推导不从函数类型中推导模板类型,有解决方法吗?
模板参数推导期间不执行隐式转换,除了:temp.deduct.call
In general, the deduction process attempts to find template argument values that will make the deduced A identical to A (after the type A is transformed as described above). However, there are three cases that allow a difference:
- If the original P is a reference type, the deduced A (i.e., the type referred to by the reference) can be more cv-qualified than the transformed A.
- The transformed A can be another pointer or pointer to member type that can be converted to the deduced A via a function pointer conversion ([conv.fctptr]) and/or qualification conversion ([conv.qual]).
- If P is a class and P has the form simple-template-id, then the transformed A can be a derived class of the deduced A. Likewise, if P is a pointer to a class of the form simple-template-id, the transformed A can be a pointer to a derived class pointed to by the deduced A.
但是,如果模板形参不参与模板实参推导,则会进行隐式转换:(temp.arg.explicit)
Implicit conversions (Clause [conv]) will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter type contains no template-parameters that participate in template argument deduction. [ Note: Template parameters do not participate in template argument deduction if they are explicitly specified.
因此,如果您显式指定模板参数,它应该可以工作:
stdfunc_test<int>([](int _) {return _ + 2;});
stdfunc_test<int>(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;
}
你可以在这里现场试用:http://fiddle.jyt.io/github/d4ab355eb2ab7fc4cc0a48da261f0127