2015-07-13 12 views
29

In JavaScript ES6 gibt es eine Sprachfunktion, die als destructuring bekannt ist. Es existiert auch in vielen anderen Sprachen.Wie kann ich Destrukturierung in C++ emulieren?

In JavaScript ES6, sieht es wie folgt aus:

var animal = { 
    species: 'dog', 
    weight: 23, 
    sound: 'woof' 
} 

//Destructuring 
var {species, sound} = animal 

//The dog says woof! 
console.log('The ' + species + ' says ' + sound + '!') 

Was kann ich in C++ tun eine ähnliche Syntax zu erhalten und diese Art von Funktionalität zu emulieren?

+0

In C++ Sie Betreiber überlasten. Wenn Sie eine 'Struktur' definieren und ihren Zuweisungsoperator entsprechend überladen, können Sie möglicherweise erreichen, was Sie anstreben. Nicht sicher, dachte. Aber Sie könnten vielleicht in diese Richtung forschen. – Elyasin

+1

Check out std :: tie – rici

+0

Python und Ruby erlaubt auch die Zuweisung zu Tupeln, aber ich denke, dass diese * Destrukturierung * Syntax ist ziemlich einzigartig für JS ... –

Antwort

32

Für den speziellen Fall von std::tuple (oder std::pair) Objekten, C++ bietet die std::tie Funktion, die ähnlich aussieht:

std::tuple<int, bool, double> my_obj {1, false, 2.0}; 
// later on... 
int x; 
bool y; 
double z; 
std::tie(x, y, z) = my_obj; 
// or, if we don't want all the contents: 
std::tie(std::ignore, y, std::ignore) = my_obj; 

Ich bin mir nicht bewusst einer Annäherung an die Notation genau wie Sie es präsentieren.

+0

Sie können 'make_tie' zu' animal' hinzufügen, das eine 'tie' zurückgibt. – Yakk

+0

Die Notation ist nicht wichtig. Nur die Semantik. Um fair zu sein, sieht die JavaScript-Notation für die Destrukturierung etwas komisch aus. Die meisten Sprachen verwenden entweder nur den Komma-Operator: 'x, y = z' oder geschweifte Klammern' (x, y) = z' – slebetman

+1

@slebetman Das JS-Beispiel destrukturiert die Eigenschaften eines Objekts. Einfaches Verwenden des üblichen durch Kommas getrennten Objekts wäre undefiniert, da Objektschlüssel keine Reihenfolge haben. – Kroltan

6

Meist dort mit std::map und std::tie:

#include <iostream> 
#include <tuple> 
#include <map> 
using namespace std; 

// an abstact object consisting of key-value pairs 
struct thing 
{ 
    std::map<std::string, std::string> kv; 
}; 


int main() 
{ 
    thing animal; 
    animal.kv["species"] = "dog"; 
    animal.kv["sound"] = "woof"; 

    auto species = std::tie(animal.kv["species"], animal.kv["sound"]); 

    std::cout << "The " << std::get<0>(species) << " says " << std::get<1>(species) << '\n'; 

    return 0; 
} 
2

Ich fürchte, Sie können es nicht so haben, wie Sie es in JavaScript gewohnt sind (was übrigens scheint new technology in JS). Der Grund dafür ist, dass in C++ Sie nicht einfach auf mehrere Variablen innerhalb einer Struktur/Objekt/Zuweisungsausdruck zuordnen können, wie Sie in

tat
var {species, sound} = animal 

und dann species und sound als einfache Variablen verwenden. Derzeit hat C++ diese Funktion einfach nicht.

Sie könnten Strukturen und/oder Objekten zuweisen, während Sie ihren Zuweisungsoperator überladen, aber ich sehe keinen Weg, wie Sie dieses genaue Verhalten (ab heute) nachahmen könnten. Betrachten Sie die anderen Antworten, die ähnliche Lösungen anbieten; vielleicht funktioniert das für Ihre Anforderung.

struct Example 
{ 
    int foo; 
    int bar; 
}; 

Example testObject; 

int DESTRUCTURE2(foo, bar, testObject); 

wodurch man lokale Variablen von foo und bar:

+0

Es gibt Vorschläge, die der Syntax des OPs in C++ sehr nahe kommen. Dies hat wenig mit starker Typisierung zu tun. – Yakk

+0

Könnten Sie bitte erläutern? Auch Referenzen wären gut zum Verständnis. In C++ müssen die Typen * (in einer Zuweisung) * übereinstimmen. Meiner Meinung nach ist das restriktiver. Im Moment erwarte ich, dass sich die Vorschläge nicht zu sehr von den anderen Antworten unterscheiden werden, die hier veröffentlicht werden. – Elyasin

+0

Nein, Typen müssen in einer Zuweisung nicht übereinstimmen? 'struct foo {Leeroperator = (int x) {std :: cout << x << '\ n';}}; foo f; f = 3;} '? Noch im Aufbau. Ich lese jemanden, der davon redet, dass es möglich ist, eine Reihe von (benannten) Werten "zu binden" ("tie-like construction"), und welche Art von Syntaxänderung erforderlich wäre. Aber es ist die ganze Syntax, die das Problem ist, mehr als die Semantik. – Yakk

1

Eine andere Möglichkeit könnte als

#define DESTRUCTURE2(var1, var2, object) var1(object.var1), var2(object.var2) 

, die wie verwendet werden würde geschehen.

Natürlich ist es auf die Erstellung von Variablen des gleichen Typs beschränkt, obwohl ich denke, Sie könnten auto verwenden, um das zu umgehen.

Und dieses Makro ist auf genau zwei Variablen beschränkt. Sie müssten also DESTRUCTURE3, DESTRUCTURE4 usw. erstellen, um so viele zu erfassen, wie Sie möchten.

Ich persönlich mag nicht den Code-Stil, mit dem dies endet, aber es kommt einigermaßen nah an einige der Aspekte der JavaScript-Funktion.

15

In C++ 17 wird diese structured bindings genannt, die für die folgenden erlaubt:

struct animal { 
    std::string species; 
    int weight; 
    std::string sound; 
}; 

int main() 
{ 
    auto pluto = animal { "dog", 23, "woof" }; 

    auto [ species, weight, sound ] = pluto; 

    std::cout << "species=" << species << " weight=" << weight << " sound=" << sound << "\n"; 
}