Mit Zügen in C ++
-
21-09-2019 - |
Frage
Diese Frage bezieht sich auf meine letzte ein . Ich versuche, das Problem mit traits<T>
und traits<T*>
zu lösen. Bitte beachten Sie den folgenden Code ein.
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
nehmen statt const foo*
. Was mache ich falsch hier?
Jede Hilfe wäre toll!
Lösung
Die Spezialisierung verwendet wird. traits<foo*>::const_reference
ist const foo
. Wenn Sie wollen, dass es ein Zeiger sein, zu verwenden:
template<typename T>
struct traits<T*>
{
typedef const T* const_reference;
};
Damit wird traits<foo*>::const_reference
const 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. Man könnte es umbenennen:
template<typename U>
struct traits<U*>
{
typedef const U* const_reference;
};
und Sie haben die gleiche Spezialisierung haben. Es macht mehr Sinn, wenn Sie Erfahrung in der funktionalen Programmierung haben.
Um zu beginnen, denken Sie an der template <typename ...>
als eine Abstraktion der Einführung, eher wie eine Funktion Abstracts aus einem Wert. Es ist wie das Drehen
sum = 0
for item in [1,2,3]:
sum += item
in:
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
von einer anderen Funktion aufrufen, die selbst einen formalen Parameter namens l
hat:
function sumsq(l):
return sum(map(lambda x: x*x, l))
sumsq
der "l" hat nichts mit sum
des "l" zu tun.
Mit Vorlagen, wir abstrakte Typnamen anstatt Werte. Das heißt, wir drehen:
struct traits {
typedef const double& const_reference;
};
in:
template <typename T>
struct traits {
typedef const T& const_reference;
};
Betrachten wir nun eine Nicht-Template-Spezialisierung:
template <>
struct traits<double*> {
typedef const double* const_reference;
};
Hier gibt es keine Template-Parameter für die Spezialisierung, aber Sie können von traits<double*>
denken als eine traits
Vorlage auf ein double*
Anwendung. Auszug aus dem double
und Sie haben:
template <typename T>
struct traits<T*> {
typedef const T* const_reference;
};
Hier ist der T
ist ein Parameter für die Spezialisierung, nicht die Basisvorlage.