2014-02-24 8 views
5

Bitte beachten Sie den folgenden Code ein:Benutzerdefinierte Wörtliche für Zwei-Argument Constructor

#include <iostream> 

class Point 
{ 
public: 
    int x,y; 
    Point(int newx, int newy) : x(newx), y(newy) {} 
}; 

Point operator"" x(const unsigned long long i) 
{ 
    return Point(i, 0); 
} 

int main() 
{ 
    Point p = 5x; 

    std::cout << "\npoint is " << p.x << "," << p.y << "\n\n"; 

    return 0; 
} 

Die UDL funktioniert, aber ist es möglich, es für Punkt für beide Argumente des Konstruktors funktioniert? z.B. 3x5 ist ein Literal für Point(3,5) oder vielleicht sogar 3.5x und dann etwas Mathe im Operator Körper zu tun, um den ganzen Teil vom Dezimalteil des Floats zu trennen ..?

+9

Verwenden Sie die Aggregat-Initialisierung, z. B. "Point p = {3,5}". Viel besser IMO als irgendein intransparentes Literal. – Paranaix

+0

@Paranaix Ich hatte keine Ahnung, dass du das kannst! Ist das ein neues Feature in C++ 11? –

+3

@ 1.618 Im allgemeinen Fall ja (genauso wie UDLs); Das nennt man * list initialization. * Aber wenn man alle Konstruktoren aus der Klasse entfernt (was für eine solche einfache Struktur sinnvoll sein könnte), werden die geschweiften Klammern als * aggregate initialization * interpretiert, was seit C++ 98 funktioniert hat. – Angew

Antwort

2

Beachten Sie zunächst, dass der Name, den Sie für eine UDL angeben, mit einem Unterstrich beginnen muss.

Ja, es ist möglich, aber es kann offen sein zu fragen, ob Sie wirklich wollen.

Point operator"" _x(long double x) { 
    return Point(floor(x), (x-floor(x))*10); 
} 

int main(){ 
    auto p = 3.5_x; 
} 

Warum Sie nicht möchten. Im Moment macht dies eine feste Multiplikation mit 10, um den Bruchteil der Fließkommazahl in eine Ganzzahl zu verwandeln. Wenn Sie etwas wie 1.23 setzen, haben Sie wahrscheinlich erwartet y zu 23, aber dies wird 2.3 stattdessen geben.

Schlimmer noch, die Zahl, die Sie im Quellcode angegeben haben, kann sich im Binärformat leicht in eine sich wiederholende Zahl verwandeln. Es gibt also fast keine Möglichkeit, vom Bruchteil einer Gleitkommazahl auszugehen und sicher zu sein, dass Sie ursprünglich produzieren beabsichtigt.

Mit einer Gleitkommazahl scheint es auf diese Weise auch keinen vernünftigen Weg zu geben, einen Punkt wie (3, -5) zu bezeichnen. Die Eingabe erlaubt nur ein Zeichen für die gesamte Nummer.

Sie könnten dies so definieren, dass stattdessen eine Zeichenfolge verwendet wird, und dann die Zeichenfolge zur Laufzeit analysieren, um den richtigen Wert zu erhalten.

auto p = "3x5"_x; 

Die meisten Leute mögen diese Option jedoch nicht wirklich. Die Eingabe in Anführungszeichen Art von Ruinen Dinge zu schließen. Wenn Sie dies trotzdem tun wollen, würde der Code wie folgt aussehen:

Point operator"" _x(char const * const s, unsigned long long len) { 
    int x, y; 
    sscanf(s, "%dx%d", &x, &y); 
    return Point(x, y); 
} 

Natürlich könnten Sie es vorziehen, das Parsen mit etwas anderem als sscanf zu tun. Ich habe das einfach schnell ausgetüftelt, um die Syntax zu zeigen, und nicht als Tutorial beim String-Parsing.

+0

Danke. Ihr String-Beispiel ist, was ich ursprünglich vorhatte.Aber jetzt, wo ich weiß, dass ich einen Initialisierer wie {3,5} verwenden kann, werde ich das stattdessen verwenden. –

1

Vielleicht durch einen willkürlichen Betreiber Überlastung:

class Point 
{ 
public: 
    int x,y; 
    Point(int newx, int newy) : x(newx), y(newy) {} 
}; 

Point operator&(Point p1, Point p2) 
{ 
    return Point(p1.x, p2.y); 
} 

Point operator"" _x(const unsigned long long i) 
{ 
    return Point(i, 0); 
} 

Point operator"" _y(const unsigned long long i) 
{ 
    return Point(0, i); 
} 

Verbrauch:

Point p = 5_x & 42_y; 

Aber im Ernst, ich sehe kein Sinn, dies zu tun, ist es Typisierung ist zumindest. Was ist los mit guten alten Point(x,y);?

+0

Der Punkt ist der 'k0ln3z' Faktor von ** erfordert ** einen C++ 11 Compiler – 6502