2016-07-11 10 views
3

Ich habe eine Reihe von Vorlagenfunktionen geschrieben. Beispiel:Vorlage Argumentableitung fehlgeschlagen, mit Funktionszeiger als Argument

template <typename T> 
inline int Foo(T* t, unsigned char** p, size_t* size, size_t (*MyHandler)(T*)) 
{ 
    ... 
} 

template <> 
inline int Foo<Bar>(Bar* t, unsigned char** p, size_t* size, size_t (*MyHandler)(Bar*)) 
{ 
    ... 
} 

Wenn ich diese Funktionen mit expliziten Template-Argumente nennen dann funktioniert alles gut, das heißt

Foo<Bar>(&myBar, pBuffer, size, FooFoo<Bar>); 

FooFoo<T> eine andere Templat-Funktion

Es wäre sehr vorteilhaft sein, wenn ein Benutzer nicht den Überblick über Typen halten müsse. So würde Ich mag die folgende Syntax verwenden:

Foo(&myBar, pBuffer, size, FooFoo); 

Allerdings ist diese Linie ein Paar

  • C2784 verursacht: konnte nicht Template-Argument für 'T *' von 'Bar *' ableiten
  • C2796: kann nicht Funktions-Template ‚size_t FooFoo (T *) als Funktion Argument

wie bei Foo verwenden gibt es eine Spezialisierung FooFoo<Bar>

Meiner Kenntnis nach sollte es möglich sein, T abzuleiten, wegen des ersten Arguments, das vom Typ T* ist - Oder ist dieser Funktionszeiger mit dem Abzug verpfuscht?

Alle Hinweise würden sehr geschätzt werden.

Update 3 Ein MCVS nach der Anfrage mit Änderungen von @Yakk vorgeschlagen, die endlich funktioniert!

#include <stdio.h> 

struct Bar 
{ 
    int a; 
    int b; 
    int c; 
}; 


template<class T>struct id_t{typedef T type;}; 

template <typename T> 
inline size_t FooFoo(T* t) 
{ 
    printf("FooFoo calculating size of T...\r\n", sizeof(T)); 
    return sizeof(T); 
} 

template <> 
inline size_t FooFoo<Bar>(Bar* t) 
{ 
    printf("FooFoo calculating size of Bar...\r\n", sizeof(Bar)); 
    return sizeof(Bar); 
} 

template <typename T> 
inline int Foo(T* t, unsigned char** p, size_t* size, typename id_t<size_t (*)(T*)>::type MyHandler) 
{ 
    printf("Foo telling size of T: %u\r\n", MyHandler(t)); 
    return 0; 
} 

template <> 
inline int Foo<Bar>(Bar* t, unsigned char** p, size_t* size, typename id_t<size_t (*)(Bar*)>::type MyHandler) 
{ 
    printf("Foo telling size of Bar: %u\r\n", MyHandler(t)); 
    return 0; 
} 



int main(int argc, char* argv[]) 
{ 
    int i; 
    Bar myBar; 

    Foo<Bar>(&myBar, nullptr, 0, FooFoo<Bar>); // works 
    Foo<int>(&i, nullptr, 0, FooFoo<int>); // works 

    Foo(&myBar, nullptr, 0, FooFoo<Bar>); // works 
    Foo(&i, nullptr, 0, FooFoo<int>); // works 


    Foo(&myBar, nullptr, 0, FooFoo); // error C2896: 'int Foo(T *,unsigned char **,size_t *,size_t (__cdecl *)(T *))' : cannot use function template 'size_t FooFoo(T *)' as a function argument 
             // error C2784: 'int Foo(T *,unsigned char **,size_t *,size_t (__cdecl *)(T *))' : could not deduce template argument for 'T *' from 'Bar *' 

    Foo(&i, nullptr, 0, FooFoo);  // error C2896: 'int Foo(T *,unsigned char **,size_t *,size_t (__cdecl *)(T *))' : cannot use function template 'size_t FooFoo(T *)' as a function argument 
             //error C2784: 'int Foo(T *,unsigned char **,size_t *,size_t (__cdecl *)(T *))' : could not deduce template argument for 'T *' from 'int *' 

    return 0; 
} 

Vielen Dank!

+1

Nur neugierig, aber haben Sie versucht 'Foo (& myBar, pBuffer, Größe, FooFoo );'? – Amadeus

+0

Kann nicht mit g ++ 5 reproduziert werden.1 (TDM), clang oder VC2015 - Bitte fügen Sie ein [Minimum, Complete und Verifable Beispiel] (http://stackoverflow.com/help/mcve) und detaillierte Informationen über Ihren Compiler zu Ihrem Post, so dass wir nicht machen müssen Raten Sie, was falsch ist. – Holt

+0

@Holt Ich habe mit Details aktualisiert, der Compiler ist MSVC 2012 – antipattern

Antwort

2

Alle Argumente haben das gleiche Gewicht bei der Ableitung und werden unabhängig abgeleitet. unter Verwendung eines bestimmten Argument für den Abzug zu blockieren, dies zu tun:

template<class T>struct id_t{typedef T type;}; 
template<class T>using block_deduction=typename id_t<T>::type; 

Nun nehmen Sie size_t (*MyHandler)(T*) und machen es:

block_deduction<size_t (*)(T*)> MyHandler 

oder in einer nicht-C++ 11-Compiler:

typename id_t<size_t (*)(T*)>::type MyHandler 

Was dies tut, ist der MyHandler Argument-Typ in einen nicht-abgeleiteten Kontext. Daher versucht der Compiler nicht und verwendet stattdessen die Ableitung des ersten Arguments, um T zu bestimmen. Dies erzeugt dann den Typ MyHandler. Die Überladungsmenge, die Sie übergeben, wird dann basierend auf der Signatur aufgelöst, und alles funktioniert (wahrscheinlich).

+0

Welche Art von schwarzer Magie ist das? Ich werde es versuchen ... aber morgen. – antipattern

+0

Vielen Dank für das Hinzufügen einer Erklärung. Muss ich die block_deduction auch im Falle des spezialisierten Foo oder nur bei der Deklaration des generischen Templates Foo verwenden? Weil Intellisense einen Fehler anzeigt, wenn ich es in der Deklaration von spezialisiertem Foo verwende ("Keine Instanz der Funktionsdeklaration stimmt mit dem angegebenen Typ überein"). – antipattern

+0

Offenbar unterstützt meine Version von Visual Studio dies nicht. Schade:/Gibt es eine Möglichkeit, das Schlüsselwort using loszuwerden? – antipattern

1

Ihr Problem ist nicht der Abzug von T=Bar für Foo - es ist der Abzug für FooFoo.

+0

Okay, ich hatte diesen Verdacht auch. Auf der anderen Seite, wenn ich im zweiten Aufruf Foo halte, dann zeigt Intellisense eine korrekt abgeleitete Signatur: 'Foo (Bar * t, unsignierter char pBuffer, size_t size, size_t (* MyHandler) (Bar *))'. – antipattern