Template type inference using std :: function

I found the following behavior with std::function and deduction type, which was unexpected for me:

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

Both lines in main result in an error:

no instance of the stdfunc_test function template matches the argument list

When trying to compile in Visual Studio 2015.

Why doesn't the type of output infer the type of the template from the type of the function, and is there a workaround?

+7
source share
2 answers

Implicit conversion is not performed when the template argument is output, with the exception of: temp.deduct.call

In general, the deduction process tries to find the values โ€‹โ€‹of the template arguments that will make the output of A identical to A (after type A conversion, as described above). However, there are three cases that allow the difference:

  • If the source P is a reference type, the deduced A (i.e. the type referenced by the reference) may be more cv-qualified than the converted A.
  • Converted A can be another pointer or pointer to a member type that can be converted to deduced A by conversion of a function pointer ([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 output A. Similarly, if P is a pointer to a class of the form simple-template-id, the converted A can be a pointer to a derived class, which indicates inferred A.

However, if the template parameter is not involved in the output of the template argument, an implicit conversion will be performed: ( temp.arg.explicit )

Implicit conversions (Clause [conv]) will be performed on the function argument to convert it to the type of the corresponding function parameter if the parameter type does not contain template parameters that are involved in the output of the template argument. [Note. Template parameters do not participate in the output of the template argument if they are explicitly specified.

So, if you explicitly specify a template argument, it should work:

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

You can use templates to display the signature of functions and functors:

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

you can try it here: http://fiddle.jyt.io/github/d4ab355eb2ab7fc4cc0a48da261f0127

+2
source

All Articles