2016-07-29 18 views
5

Ich versuche, einen spezialisierten Konstruktor für std::string Argumente zu erstellen, aber der andere wird immer verwendet, wenn ich es mit einem String-Argument aufrufen. C++ - Konstruktor Vorlage Spezialisierung

struct Literal : Expression 
{  
    template <typename V> 
    Literal(V val) 
    { 
     value = val; 
    } 
}; 

template <> 
Literal::Literal(std::string const& val) 
{ 
    value = val.c_str(); 
} 

Es spielt keine Rolle, ob innerhalb der Klasse definiert werden, die beide außerhalb der Klasse, oder wie in dem entsandten Beispiel nur die Spezialisierung außerhalb der Klasse definiert ist: Wenn sie mit std::string genannt, die Zuordnung value = val gibt ein Compilerfehler

Wie spezialisiere ich diese Konstruktorvorlage für std::string richtig?

+0

Sie nicht erklären 'value'. Dies ist der Fehler, den Sie erhalten: _main.cpp: 12: 9: error: 'value' wurde in diesem Bereich nicht angegeben value = val; _ –

+0

@HenriqueBarcelos 'ATL :: CComVariant value' wird in' Expression' deklariert . Ich habe nur die relevanten Vorlagen zur Verfügung gestellt. –

+0

Ich nehme an, "Wert" ist in der Basisklasse definiert. – Bathsheba

Antwort

6

Sie nicht.

sollten Sie Überlastung des Konstruktor: Literal(const std::string&), die Sie in der struct Erklärung tun.

Der Compiler versucht immer, Nicht-Template-Überlastungen vor Template-Einsen zu vergleichen.

+0

Es gibt keine Bearbeitung und ich sehe keinen Nicht-Vorlage-Konstruktor? – kfsone

+0

Sorry, ich habe die Antwort klarer gemacht. – Bathsheba

+0

Meine Verwirrung ist diese: Er hat nur den einen Konstruktor, und es ist templated, er versucht, es zu spezialisieren, so dass die Wahl des Compilers zwischen der deklarierten Deklaration/Definition in der Klasse oder der Spezialisierung davon ist - wo ist die Nicht-Template-Überlastung Gelegenheit? – kfsone

1

Viele Male, wenn Überlastung eine Lösung ist, versuchen die Leute, die volle Spezialisierung zu definieren. Aber Überlastung könnte eine viel bessere Lösung sein. In Ihrem Fall würde ich einen neuen Konstruktor mit dem String-Parameter erstellen. Beachten Sie, dass nur die Basisvorlage in Überladungsauflösung berücksichtigt wird. Der folgende Artikel ist eine gute Referenz, diese Idee zu verstehen: http://www.gotw.ca/publications/mill17.htm

UPDATE:

Wie auch immer, meine Antwort zu verbessern, können Sie die folgende Basisvorlage Konstruktor versuchen:

template <typename V> 
Literal(V const& val) 
{ 
    value = val; 
} 
4

Nach dem standard, 14.8.2.1 Ableiten von Vorlagenargumenten von einem Funktionsaufruf [temp.deduct.call] Dabei ist P der Vorlagenparameter und A ist das Funktionsaufrufargument an dieser Position:

2 If P is not a reference type:

If A is an array type, the pointer type produced by the array-to-pointer = standard conversion ([conv.array]) is used in place of A for type deduction; otherwise,

If A is a function type, the pointer type produced by the function-to-pointer standard conversion ([conv.func]) is used in place of A for type deduction; otherwise,

If A is a cv-qualified type, the top-level cv-qualifiers of A's type are ignored for type deduction.

If P is a cv-qualified type, the top-level cv-qualifiers of P's type are ignored for type deduction. If P is a reference type, the type referred to by P is used for type deduction. [...]

So gegeben

std::string s{"hello"}; 
const std::string& sr{s}; 
Literal l(sr); 

A (sr) ist const std::string& aber die Konstantheit wird nicht berücksichtigt, so dass der Compiler std::string betrachtet. Dies entspricht Ihrem

template <typename V> 
Literal(V val) 
{ 
    value = val; 
} 

und so wird diese Spezialisierung verwendet. Wenn Sie

template<> 
Literal(std::string val) 

der Compiler spezialisiert hatte, würde diese Spezialisierung finden, und das ist wahrscheinlich das, was Sie zu tun haben, und bewegen Semantik zu verwenden.

#include <iostream> 
#include <string> 

struct S { 
    template<typename T> 
    S(T t) { std::cout << "T t\n"; } 

    std::string value_; 
}; 

template<> 
S::S(std::string value) { 
    std::cout << "string\n"; 
    value_ = std::move(value); 
} 

template<> 
S::S(const std::string&) { 
    std::cout << "const string&\n"; 
} 

int main() { 
    S s1(42); 

    std::string foo{"bar"}; 
    const std::string& foor = foo; 
    S s2(foo); 
    S s3(foor); 
} 

http://ideone.com/eJJ5Ch

+0

Danke, das ist eine korrekte Antwort! Allerdings hatte ich kein Problem mit gcc toolchain. Nur wenn ich nach Klängen portierte, musste ich nach der Antwort suchen. – foxfireee

Verwandte Themen