2017-03-25 3 views
3

Ich möchte eine Template-Funktion schreiben, um Daten von einem Array in ein anderes Array zu kopieren. Ich will nur int, double und char* (String) Arrays in meinem Programm behandeln.C++: Kann einen Parameter vom Typ 'char *' nicht mit einem Lvalue vom Typ 'double' in einer Template-Funktion mit dem Typ konditional initialisieren

template<typename T> 
void copy_key(T *destination, int destination_index, T *source, int source_index){ 
    if (typeid(T) == typeid(int) or typeid(T) == typeid(double)){ 
     destination[destination_index] = source[source_index]; 
    } else { 
     // char* case 
     strcpy(destination[destination_index], source[source_index]); 
    } 
} 

Wenn ich copy_key() wie unten rufen, will ich Fehler: Kann nicht einen Parameter vom Typ ‚char *‘ mit einem L-Wert vom Typ ‚double‘ initialisieren.

int main(int argc, const char * argv[]) { 
    double from_array[3] = {1.0,2.0,3.0}; 
    double to_array[3]; 
    copy_key(to_array, 0, from_array, 2); 
    std::cout << to_array[0] << std::endl; 
    return 0; 
} 

Ich dachte, wenn Tdouble ist, würde der andere Block nicht eingegeben werden. Meine Frage ist, wie man die Bedingung für den Schablonentyp in meinem Beispiel korrekt verwendet?

+1

Der 'else' Block muss noch * kompiliert * werden.Die Auswahl 'if' erfolgt immer noch zur * Laufzeit *. Es sieht auch so aus, als ob eine Spezialisierung oder einfach nur Überladung ein besseres Design wäre, denke ich. –

+1

Die Funktion muss in der Lage sein, als Ganzes zu kompilieren. Wenn Sie den Template-Parameter "by-hand" ersetzt haben, dh eine neue Standalone-Funktion erstellt haben (mit dem Template-Parameter T substituiert), würden Sie erwarten, dass er kompiliert wird? –

Antwort

5

Ich dachte, wenn Tdouble war, würde der andere Block nicht eingegeben werden.

Sie dachten richtig. Aber Ihre Annahme über die Konsequenzen ist nicht richtig.

Nur weil einige Code nicht ausgeführt werden, bedeutet das nicht, dass es, zusammen mit dem Rest des Programms, nicht gut gebildet werden muss.

Auch wenn es in diesem Fall möglich ist, dass der Compiler beweist, dass die Zeile nicht ausgeführt wird, ist ein solcher Beweis für alle möglichen Programme im Allgemeinen praktisch unmöglich, so dass er die Korrektheit des Programms nicht beeinträchtigen kann.

Eine typische Lösung entweder Überlastungen oder Vorlagen Spezialisierungen zu verwenden:

void copy_key(char *destination, int destination_index, const char *source, int source_index){ 
    strcpy(...); 
} 

void copy_key(double *destination, int destination_index, double *source, int source_index){ 
    destination[destination_index] ... 
} 

In der kommenden C++ 17, wird es constexpr if sein, die Blöcke innerhalb einer einzigen Funktion bedingt kompiliert ermöglicht.

3

In C++ 17 erhalten Sie if constexpr, die nur einen Zweig der If-Anweisung ausgewertet.

Im Moment müssen sowohl der if-part als auch der else-part ein gültiger Code für den Typ T sein. Wenn Sie möchten, dass es sich für verschiedene Typen anders verhält, müssen Sie die Vorlage spezialisieren.

3

Verwenden Sie in C++ 14 und vorher template specialization anstelle von Bedingungen.

C++ ist eine kompilierte Sprache, nicht interpretiert. Wenn eine templatierte Funktion für eine bestimmte konkrete Verwendung kompiliert wird, muss die gesamte Funktion kompiliert werden, nicht nur die Verzweigungen, die zufällig genommen werden. Der Compiler im Allgemeinen kann den genauen Pfad nicht ableiten, den Ihr Code für alle Eingaben a priori nehmen wird.

template<typename T> 
void copy_key(T *destination, int destination_index, T *source, int source_index){ 
    destination[destination_index] = source[source_index]; 
} 

template<> 
void copy_key(const char** destination, int destination_index, const char** source, int source_index) { 
    // char* case 
    strcpy(destination[destination_index], source[source_index]); 
} 
1

Nein, das geht nicht. Setzen Sie als:

template<typename T> 
void copy_key(T *destination, int destination_index, T *source, int source_index){ 
    if (some_condition){ // some_condition met 
     destination[destination_index] = source[source_index]; 
    } else { // some condition not met 
     // char* case 
     strcpy(destination[destination_index], source[source_index]); 
    } 
} 

ist einfacher zu sehen.

Sie brauchen eine "bedingte Kompilierung" statt (Template-Spezialisierung)

Verwandte Themen