2016-08-26 7 views
6

Ich habe das folgende Verhalten mit std::function und Typ Abzug entdeckt, was für mich unerwartet war:Vorlagentyp Abzug mit 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); 
} 

Beiden Linien in main Ergebnis in Fehlern:

no instance of function template "stdfunc_test" matches the argument list

Bei dem Versuch, in Visual Studio 2015 zu kompilieren.

Warum zieht der Typ Abzug Schablonentyp vom Funktionstyp nicht ab, und Gibt es einen Workaround dafür?

+2

Weder das Lambda noch die Funktionszeiger ist eigentlich ein 'std :: function' - Sie sind implizit in eine 'std :: -Funktion umwandelbar. – aschepler

+0

Werden implizite Konvertierungen bei der Ableitung von Template-Variablen nicht berücksichtigt? – redspah

+2

Nehmen Sie einfach an, es ist eine Funktion: 'Vorlage void stdfunc_test (T func)'. Beschränken Sie dann den Umfang der Vorlage mit SFINAE. – rustyx

Antwort

1

Keine implizite Konvertierung wird während der Vorlage Argument Abzug durchgeführt, mit der Ausnahme: 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.

Wenn jedoch der Template-Parameter beteiligt sich nicht an Template-Argument Abzug wird implizite Konvertierung durchgeführt werden: (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.

Also, wenn Sie explizit die Vorlage Argument angeben, sollte es funktionieren:

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

können Sie Vorlagen verwenden, um die Signatur von Funktionen und functors ableiten:

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

Sie können es hier leben versuchen: http://fiddle.jyt.io/github/d4ab355eb2ab7fc4cc0a48da261f0127

Verwandte Themen