2010-02-21 11 views
5

Diese Frage bezieht sich auf meine letzte one. Ich versuche das Problem mit traits<T> und traits<T*> zu lösen. Bitte beachten Sie den folgenden Code.Verwenden von Merkmalen in C++

template<typename T> 
struct traits 
{ 
    typedef const T& const_reference; 
}; 

template<typename T> 
struct traits<T*> 
{ 
    typedef const T const_reference; 
}; 

template<typename T> 
class test 
{ 
public: 
    typedef typename traits<T>::const_reference const_reference; 
    test() {} 
    const_reference value() const { 
     return f; 
    } 
private: 
    T f; 
}; 

int main() 
{ 
    const test<foo*> t; 
    const foo* f = t.value(); // error here. cannot convert ‘const foo’ to ‘const foo*’ in initialization 
    return 0; 
} 

So sieht es aus wie Compiler nicht die Züge Spezialisierung für Zeiger unter Berücksichtigung und Rückgabetyp value() als const foo statt const foo* nehmen. Was mache ich hier falsch?

Jede Hilfe wäre großartig!

Antwort

2

Die Spezialisierung wird verwendet. traits<foo*>::const_referenceistconst foo. Wenn Sie es wollen, ein Zeiger sein, verwenden:

template<typename T> 
struct traits<T*> 
{ 
    typedef const T* const_reference; 
}; 

Damit wird traits<foo*>::const_referenceconst foo* sein.

Beachten Sie, dass die Verwendung von T in der traits<T*> Spezialisierung aus dem T in der traits Vorlage vollständig getrennt ist. Sie könnten es umbenennen:

template<typename U> 
struct traits<U*> 
{ 
    typedef const U* const_reference; 
}; 

und Sie werden die gleiche Spezialisierung haben. Es macht mehr Sinn, wenn Sie Erfahrung in der funktionalen Programmierung haben.

Denken Sie zunächst an die template <typename ...> als Einführung einer Abstraktion, eher wie eine Funktion abstrahiert einen Wert. Es ist wie

sum = 0 
for item in [1,2,3]: 
    sum += item 

in Dreh:

function sum(l): 
    sum = 0 
    for item in l: 
     sum += item 
    return sum 

wo l an die Stelle der [1,2,3] nimmt. Wir können sums aus einer anderen Funktion aufrufen, die selbst einen formalen Parameter l benannt hat:

function sumsq(l): 
    return sum(map(lambda x: x*x, l)) 

sumsq 's "l" hat nichts mit sum zu tun' s "l".

Mit Vorlagen abstrahieren wir Typnamen anstelle von Werten. Das heißt, wir drehen:

struct traits { 
    typedef const double& const_reference; 
}; 

in:

template <typename T> 
struct traits { 
    typedef const T& const_reference; 
}; 

nun eine Nicht-Template-Spezialisierung berücksichtigen:

template <> 
struct traits<double*> { 
    typedef const double* const_reference; 
}; 

Hier gibt es keine Template-Parameter für die Spezialisierung sind, aber Sie können Denken Sie an traits<double*> als Anwendung einer traits Vorlage auf eine double*. Auszug aus den double und Sie haben:

template <typename T> 
struct traits<T*> { 
    typedef const T* const_reference; 
}; 

Hier ist die T ist ein Parameter für die Spezialisierung, nicht die Basisvorlage.

+0

Ich fühle dump :(Aber, T selbst ist ein Zeiger ('foo *'). Also die Angabe von 'T *' wird in 'T **' führen? –

+0

Nein. In der 'Traits ' Spezialisierung, 'T 'ist kein Zeiger,' T * 'ist ein Zeiger. Dass Sie den gleichen typename Parameter verwenden, ist belanglos. – outis

+0

OK. Danke. Es macht jetzt Sinn. –

Verwandte Themen