2009-10-12 9 views
9

Ich bin auf der Suche nach einer einfachen Möglichkeit, ein Array von Zeichenfolgen zur Kompilierzeit zu erstellen. Für einen Test habe ich eine Klasse mit dem Namen Strings zusammen, die folgenden Mitglieder hat:Missbrauch der Komma-Operator

Strings(); 
Strings(const Strings& that); 
Strings(const char* s1); 
Strings& operator=(const char* s1); 
Strings& operator,(const char* s2); 

diese verwenden, kann ich erfolgreich Code wie folgt zusammenstellen:

Strings s; 
s="Hello","World!"; 

Der s="Hello" Teil die operator= ruft die zurück a Strings& und dann die operator, für "World!" abgerufen werden.

Was kann ich nicht an die Arbeit (in MSVC, haben alle anderen Compiler noch nicht ausprobiert) ist

Strings s="Hello","World!"; 

Ich würde hier davon aus, dass Strings s="Hello" den Kopierkonstruktor nennen würde und dann würde alles verhalten das gleiche wie im ersten Beispiel. Aber ich habe den Fehler: error C2059: syntax error : 'string'

Das funktioniert aber fein:

Strings s="Hello"; 

So weiß ich, dass die Kopie Konstruktor tut zumindest Arbeit für einen String. Irgendwelche Ideen? Ich möchte wirklich, dass die zweite Methode funktioniert, nur um den Code ein wenig sauberer zu machen.

+8

Wow, ich habe eine Menge Witze über das Überladen der Komma-Operator gehört. Ich hätte nie erwartet, dass jemand es tatsächlich tun würde. –

+2

@Carl: Was ist mit http://www.boost.org/doc/libs/1_40_0/libs/assign/doc/index.html#intro (sehr viel wie etwas OP will) – UncleBens

+0

* schaudern * Nägel in Ihre eigenen Sarg. Wie wirst du das debuggen, wenn es falsch läuft? –

Antwort

14

Ich denke, dass das Komma in Ihrem zweiten Beispiel nicht der Komma-Operator, sondern das Grammatikelement für mehrere Variablendeklarationen ist.

zB die gleiche Art und Weise, die Sie schreiben können:

int a=3, b=4 

Es scheint mir, dass Sie das Schreiben im Wesentlichen:

Strings s="Hello", stringliteral 

So der Compiler den Punkt nach dem Komma erwartet das sein Name einer Variablen und stattdessen sieht sie ein String-Literal und kündigt einen Fehler an. Mit anderen Worten, der Konstruktor wird auf "Hello" angewendet, aber das Komma ist danach nicht der Komma-Operator von Strings.

Übrigens ist der Konstruktor nicht wirklich ein Kopierkonstruktor. Es erstellt ein Strings-Objekt aus einem Literal-String-Parameter ... Der Begriff Copy-Konstruktor wird normalerweise auf denselben Typ angewendet.

+2

Es besteht die Gefahr, pedantisch zu werden, 'Strings s =" Hello ";' entspricht "Strings s = Strings (" Hello ");'. Es erfordert, dass der copy ctor aufrufbar ist, und könnte es sogar aufrufen, 's' aus einem temporären Objekt zu konstruieren. Aber die Optimierung, um es durch direkte Initialisierung zu ersetzen, indem man den 'const char *' -Konstruktor für 's' verwendet, ohne irgendwelche temporären, ist erlaubt und üblich. –

+0

Duh, ich kann nicht glauben, dass ich das nicht gesehen habe. – miked

8

Ich würde diese Art von API nicht empfehlen. Sie werden weiterhin Fälle ermitteln, die nicht wie erwartet funktionieren, da Komma der Operator mit der niedrigsten Priorität ist.Zum Beispiel wird dieser Fall nicht funktionieren:

if ("Hello","world" == otherStrings) { ... } 

Sie können in der Lage sein, die Dinge zum Laufen zu bringen, wenn Sie Klammern jedes Mal, um den Satz von Saiten verwenden, wie folgt aus:

Strings s=("Hello","World!"); 

Und meine Beispiel oben würde wie folgt aussehen:

if (("Hello","world") == otherStrings) { ... } 

, die wahrscheinlich gemacht werden kann, arbeiten, aber die Stenografie Syntax ist wahrscheinlich nicht wert, die heikele Semantik, die mit ihm gekommen.

+3

Kann das funktionieren? Das Problem, das ich sehe, ist, dass man 'operator' nicht überladen kann, denn' const char * ', also' ("Hello", "world") 'ist genau dasselbe wie' "world" '. –

+0

Ich nahm an, dass Sie den Operator überladen können (const char *, const char *). Gibt es einen Grund, warum das nicht möglich ist? Ich mache nicht viel C++ - Programmierung, um ehrlich zu sein. –

0

Sie könnten eine Reihe von Zeichenzeiger

Strings::Strings(const char* input[]); 

const char* input[] = { 
    "string one", 
    "string two", 
    0}; 

Strings s(input); 

und innerhalb des Konstruktors verwenden, durch die Zeiger durchlaufen, bis Sie die null getroffen.

+0

Oder Vorlage der Konstruktor: 'Vorlage Strings (const char * (& Eingabe) [N]) {für (int i = 0; i

+0

Oh, oder natürlich könnte die Konstruktorvorlage eine andere Funktion aufrufen, ähnlich wie 'vector :: insert (iterator, InputIterator, InputIterator) ', um zu vermeiden, dass doppelter Code erzeugt wird, wenn Sie ihn an verschiedenen Stellen mit vielen verschiedenen Längen aufrufen. –

0

Wenn Sie C++ 0x, haben sie neue inializer lists für diese! Ich wünschte, du könntest diese benutzen. Zum Beispiel:

std::vector<std::string> v = { "xyzzy", "plugh", "abracadabra" }; 
std::vector<std::string> v{ "xyzzy", "plugh", "abracadabra" }; 
0

Wenn die einzige Aufgabe von Strings ist eine Liste von Strings zu speichern, dann könnte boost::assign tun, um die Arbeit besser mit Standard-Containern, denke ich :)

using namespace boost::assign; 
vector<string> listOfThings; 
listOfThings += "Hello", "World!"; 
1

Es ist möglich zu machen diese Arbeit, für eine ausreichend lose Definition von "Arbeit". Hier ist ein Arbeitsbeispiel, das ich vor einigen Jahren auf eine ähnliche Frage geschrieben habe. Es hat Spaß gemacht, als Herausforderung, aber ich würde es nicht in echten Code verwenden:

#include <iostream> 
#include <algorithm> 
#include <iterator> 
#include <vector> 

void f0(std::vector<int> const &v) { 
    std::copy(v.begin(), v.end(), 
     std::ostream_iterator<int>(std::cout, "\t")); 
    std::cout << "\n"; 
} 

template<class T> 
class make_vector { 
    std::vector<T> data; 
public: 
    make_vector(T const &val) { 
     data.push_back(val); 
    } 

    make_vector<T> &operator,(T const &t) { 
     data.push_back(t); 
     return *this; 
    } 

    operator std::vector<T>() { return data; } 
}; 

template<class T> 
make_vector<T> makeVect(T const &t) { 
    return make_vector<T>(t); 
} 

int main() { 
    f0((makeVect(1), 2, 3, 4, 5)); 
    f0((makeVect(1), 2, 3)); 
    return 0; 
} 
Verwandte Themen