2012-04-17 1 views
5

Ich versuche, Spezialisierungen zusammen zu gruppieren, um zu vermeiden, sie mehrmals zu schreiben. Zum Beispiel versuche ich im folgenden Code "float" und "double" als einen Fall der Implementierung für foo :: func() zu spezialisieren; Ich verwende dann eine andere Implementierung für "bool".Warum zählt dieser abhängige Typ nicht als Spezialisierung mit dem Template-Argument?

template<typename T> struct foo; 

template<typename T> struct bar; 
template<> struct bar<float> { typedef float Type; }; 
template<> struct bar<double> { typedef double Type; }; 

/* specialize for float and double here */ 
template<typename T> struct foo<typename bar<T>::Type> { 
    static void func() { ... } 
}; 

template<> struct foo<bool> { 
    static void func() { ... } 
}; 

Diese Fehler in GCC 4.4.3. (Dies ist ein Ziel Compiler, weil es für Ubuntu Server 10.04 LTS Lager ist, die drei Jahre angeblich zu leben hat.) Der Fehler ist:

foo.cpp:8: error: template parameters not used in partial specialization: 
foo.cpp:8: error:   ‘T’ 

Der Fehler bezieht sich auf die erste Spezialisierung von foo (für " float "und" double. ")

Ich sehe nicht, welchen Teil von C++ ich hier verletze - wenn jemand das Kapitel und den Vers kennt, würde ich es begrüßen. Wenn jemand einen anderen Weg kennt, um dasselbe Ziel zu erreichen (Wiederverwendung von Spezialisierungen für bestimmte Gruppen von Typen, ohne unnötigen ausführlichen Code), würde ich mich über Vorschläge freuen!

Antwort

6
template<typename T> struct foo<typename bar<T>::Type> { 
    static void func() { ... } 
}; 

Sie verwenden T in nicht nachvollziehbaren Kontext, daher kann der Compiler T nicht ableiten, auch wenn es den Wert bar<T>::Type kennt.

Angenommen, Sie schreiben,

foo<double> foodouble; 

dann werden Sie wahrscheinlich denken, bar die mit double spezialisiert ist, wird ausgewählt werden, wenn foo instanziieren? Das scheint nur sinnvoll, wenn der Compiler sicherstellen können, dass es keine weitere Spezialisierung der bar existiert, die double als verschachtelter Typ, etwa wie folgt definiert:

template<> struct bar<int> { typedef double Type; }; 

Jetzt bar<double>::Type und bar<int>::Type beide geben double. Die Grundlinie ist also: es könnte unendlich viele Spezialisierungen von bar existieren, die alle double als verschachtelten Typ bereitstellen können, was es unmöglich macht, dass der Compiler eindeutig das Template-Argument für bar Klassenvorlage ableitet.


können Sie verwenden SFINAE als:

#include <iostream> 

template<typename T> struct bar { typedef void type; }; 
template<> struct bar<float> { typedef bar<float> type; }; 
template<> struct bar<double> { typedef bar<double> type; }; 

template<typename T> 
struct foo : bar<T>::type 
{ 
    static void func() 
    { 
     std::cout << "primary template for float and double" << std::endl; 
    } 
}; 

template<> 
struct foo<bool> 
{ 
    static void func() 
    { 
     std::cout << "specialization for for bool" << std::endl; 
    } 
}; 

int main() 
{ 
    foo<float>::func(); 
    foo<double>::func(); 
    foo<bool>::func(); 
} 

Ausgang (online demo):

primary template for float and double 
primary template for float and double 
specialization for for bool 

Beachten Sie, dass struct foo : bar<T>::type nicht mehr eine Spezialisierung ist. Es ist eine primäre Vorlage. Beachten Sie auch, dass es möglicherweise nicht das ist, was Sie möchten, da es alle Instanziierungen der Klassenvorlage mit einem anderen Typargument als float, double und bool deaktiviert; Zum Beispiel können Sie foo<int> nicht verwenden. Aber dann habe ich auch bemerkt, dass Sie die primäre Vorlage undefined gelassen haben, also hoffe ich, dass diese Lösung zu Ihrer Anforderung passt.

+0

Ich wäre sehr glücklich, einen "mehrdeutigen Template-Spezifikation" -Fehler zu bekommen, wenn es mehrere Bars mit der gleichen Type-Deklaration gibt. Der Compiler verfügt tatsächlich über alle erforderlichen Informationen. Seltsamerweise berichtet ein Freund, dass diese Erklärung auf GCC 4.1 auf MacOS X funktioniert. Wie auch immer - danke für die Antwort und die vorgeschlagene Lösung. Es sieht so aus, als könnte das für mich funktionieren! –

2

Ich glaube nicht, dass das, was Sie versuchen, möglich ist. Ich habe eine ähnliche Frage here gefunden. Ich habe keinen Link, aber der relevante Abschnitt des C++ Standards ist 14.8.2.5. Hier ist ein Zitat aus dem Abschnitt über den Abzug der Vorlage Argumente:

The non-deduced contexts are: 
— The nested-name-specifier of a type that was specified using a qualified-id. 
— A non-type template argument or an array bound in which a subexpression references a template 
parameter. 
— A template parameter used in the parameter type of a function parameter that has a default argument 
that is being used in the call for which argument deduction is being done. 
— A function parameter for which argument deduction cannot be done because the associated function 
argument is a function, or a set of overloaded functions (13.4), and one or more of the following apply: 
— more than one function matches the function parameter type (resulting in an ambiguous deduc- 
tion), or 
— no function matches the function parameter type, or 
— the set of functions supplied as an argument contains one or more function templates. 
— A function parameter for which the associated argument is an initializer list (8.5.4) but the parameter 
does not have std::initializer_list or reference to possibly cv-qualified std::initializer_list 
type. [ Example: 
template<class T> void g(T); 
g({1,2,3}); 
// error: no argument deduced for T 
— end example ] 
— A function parameter pack that does not occur at the end of the parameter-declaration-clause. 

In Ihrem Fall Sie unter Angabe der Art, die eine qualifizierte ID verwenden, so das Argument nicht abgeleitet werden kann.

Ohne es zu viel Gedanken, als eine schnelle Abhilfe geben Sie eine zweite nicht-Typ bool Parameter foo hinzufügen könnte - wie etwas:

template<typename T, bool is_decimal = false> 
struct foo {...}; // general case 

template<typename T> 
struct foo<T, true> { ... }; // case where T is float or double 

Best of luck ...

+0

Punkte für die Referenz! Traurigkeit, dass T explizit nicht abgeleitet ist, obwohl (in diesem Fall) könnte es abgeleitet werden, und Mehrdeutigkeit oder nicht angemessen erkannt. –

Verwandte Themen