2016-04-27 7 views
7

die folgenden Arten vor:Überlastung mit typedef gibt einen Fehler

#include <iostream> 

typedef unsigned long long  usize_t; 
typedef unsigned __int16  uword_t; 
typedef uword_t     clockval_t;  // time without seconds in format HHMM 

std::string toString(clockval_t nClock) 
{ 
    return std::to_string((usize_t)nClock/100) + ":" + std::to_string((usize_t)nClock % 100); 
} 

std::string toString(uword_t nValue) 
{ 
    return std::to_string((usize_t)nValue); 
} 

void test(void) 
{ 
    uword_t val = 1; 
    clockval_t time = 1023; // 10:23 

    std::cout << "Value: " << toString(val); 
    std::cout << "time: " << toString(time); 
} 

Jetzt, wenn ich versuche, dies zu kompilieren, erhalte ich einen Fehler vom Compiler mir zu sagen, dass die std::string toString(clockval_t) bereits einen Körper hat. Ich verstehe, warum das natürlich passiert, weil der Typdef nur ein Alias ​​für uword_t ist.

AFAIK die einzigen Lösungen sind über ein separates Verfahren zur Verfügung zu stellen:

std::string toClockString(clockval_t); 

oder ein Objekt machen:

class clockval ... 

Ist das richtig oder gibt es eine andere Art und Weise der Compiler wählen die machen richtige Überlastung?

+0

Ah, die Freuden des C-Typ-Systems! – Sean

+2

Ja, IMO ist ein bisschen schwach, weil der ganze Sinn von typedefs darin besteht, neue Typen zu erstellen, damit der Compiler sie richtig unterscheiden kann, um sie konsistent zu machen. Ich denke, es gibt jedoch ein Problem mit der Rückwärtskompatibilität. – Devolus

Antwort

2

Selbst wenn es eine Möglichkeit gäbe, den Compiler für die richtige Version zu wählen, ist Ihnen klar, wie fehleranfällig das sein könnte? Zum Glück gibt es keinen solchen Weg, weil typedef Alias ​​erstellt und nichts mehr.

Ich schlage vor, dass Sie es in Klasse konvertieren. Wenn Sie die richtigen Konstruktor und Konvertierungsoperator liefern dann brauchen Sie auch nicht Teile des Codes zu ändern, die Verwendung von clockval_t machen:

class clockval_t { 
public: 
    clockval_t(uword_t aValue) : value(aValue) {} 
    operator uword_t() const { return value; } 

private: 
    uword_t value; 
}; 

... 

clockval_t time = 1023; // works fine 
std::cout << time << std::endl; // works fine 
std::cout << (time/10) << std::endl; // works fine 
+0

DANKE! Dies ist definitiv die beste Antwort.:) Ich habe den Maschinencode überprüft, um sicherzustellen, dass es keinen unnötigen Overhead im Gegensatz zu einem einfachen Wort gibt (was meine größte Sorge gegen ein Objekt gewesen wäre) und dies verhält sich genau wie ein Wort und hat die Vorteile des Typs . :) – Devolus

+0

Dies hat den Nachteil, dass Sie alle arithmetischen Operationen auf dem Clockval_t verlieren. Sie müssten jeden Operator in der Klasse neu definieren (falls erforderlich). –

0

Die Bedeutung von typedef im Standard als (7.1.3 Der typedef Spezifizierer) definiert ist:

Im Rahmen ihrer Erklärung, ist ein typedef-Name der Art mit einem Schlüsselwort und Namen syntaktisch äquivalent verbunden mit der Kennung (...). Ein typedef-name ist somit ein Synonym für einen anderen Typ. Ein typedef-name gibt keinen neuen Typ (...) ein.

Daher sind die zwei Funktionen in der Tat mehrdeutig in Bezug auf die Art der Eingabeparameter. Sie müssen den Typ unterscheiden (z. B. durch Verwendung eines anderen Typs, z. B. einer Klasse oder Enumeration) oder einen zweiten Parameter (eventuell mit einem Standardwert) hinzufügen, der angibt, welcher Typ genau übergeben wird.

Link zur ursprünglichen Antwort : https://softwareengineering.stackexchange.com/questions/254473/in-which-stage-of-compilation-is-typedef-resolved-by-the-compiler

+0

Ich mag diese Antwort wegen des Zitats, aber ich stimme der akzeptierten Antwort zu, dass das Hinzufügen eines falschen Parameters keine gute Idee ist und im Wesentlichen dem Erstellen eines bestimmten Funktionsnamens sehr ähnlich ist. – Devolus

1

Ist das korrekt oder gibt es eine andere Möglichkeit, den Compiler die richtige Überladung auszuwählen?

Ja, Sie haben recht, Sie nicht auf typedef überlasten kann, da es einfach ein Alias ​​ist. Wie Sie zu Recht vorschlagen, benennen Sie die Funktion entweder um oder erstellen Sie einen neuen Typ mit class. Hinzufügen eines gefälschten Parameter einfach um die Signatur der Funktion zu ändern ist in der Regel eine schlechte Idee, Umbenennung ist klarer.