2015-07-13 3 views
29

В JavaScript ES6 имеется языковая функция, известная как destructuring. Он существует и на многих других языках.Как я могу эмулировать деструктурирование в C++?

В JavaScript ES6, это выглядит следующим образом:

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

//Destructuring 
var {species, sound} = animal 

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

Что я могу сделать в C++, чтобы получить подобный синтаксис и эмулировать такую ​​функциональность?

+0

В C++ вы можете перегрузить операторы. Если вы определите «структуру» и перегрузите свой оператор присваивания соответственно, возможно, вы сможете достичь того, к чему вы стремитесь. Не уверен. Но вы могли бы исследовать это направление. – Elyasin

+1

Check out std :: tie – rici

+0

Python и Ruby также позволяют назначать кортежи, но я думаю, что этот синтаксис * Object destructuring * довольно уникален для JS ... –

ответ

32

Для конкретного случая std::tuple (или std::pair) объектов, C++ предлагает функцию std::tie, которая выглядит примерно так:

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; 

Я не знаю, подхода к обозначению точно так же, как вы его представляете.

+0

Вы можете добавить 'make_tie' в' animal', который возвращает 'tie'. – Yakk

+0

Обозначение не имеет значения. Только семантика. Справедливости ради, нотация javascript выглядит немного странно для деструктурирования. Большинство языков используют либо только оператор запятой: 'x, y = z' или braces' (x, y) = z' – slebetman

+1

@slebetman Пример JS разрушает свойства объекта. Простое использование разделенных запятыми значений будет неопределенным, поскольку ключи объектов не имеют порядка. – Kroltan

6

В основном там с std::map и 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

Я боюсь, что вы не можете иметь его так, как вы привыкли в JavaScript (который, кстати, кажется new technology in JS). Причина заключается в том, что в C++ вы просто не можете назначить нескольких переменных в выражении в структуре/объект/назначения, как вы делали в

var {species, sound} = animal 

, а затем использовать species и sound в простых переменных. В настоящее время C++ просто не имеет этой функции.

Вы можете назначить структуры и/или объекты при перегрузке их оператора присваивания, но я не вижу способа, как вы могли бы эмулировать это точное поведение (на сегодняшний день). Рассмотрите другие ответы, предлагающие похожие решения; возможно, это работает для вашего требования.

+0

Есть предложения добавить очень близко к синтаксису OP к C++. Это мало связано с сильной типизацией. – Yakk

+0

Не могли бы вы подробнее рассказать? Также ссылки будут полезны для понимания. В C++ типы должны * соответствовать * (в задании). По-моему, это более ограничительно. На данный момент я ожидаю, что предложения не будут сильно отличаться от других ответов, размещенных здесь. – Elyasin

+0

Нет, типы не должны совпадать в задании? 'struct foo {void operator = (int x) {std :: cout << x << '\ n';}}; foo f; f = 3;} '? Не в строительстве. Я читал, что кто-то говорил о том, чтобы позволить «связать« подобную конструкцию »из набора (названных) значений и какое изменение синтаксиса потребуется. Но все это синтаксис - это проблема, более чем семантика. – Yakk

1

Другая возможность может быть сделано как

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

, который будет использоваться как:

struct Example 
{ 
    int foo; 
    int bar; 
}; 

Example testObject; 

int DESTRUCTURE2(foo, bar, testObject); 

уступая локальные переменные foo и bar.

Конечно, он ограничен созданием переменных одного и того же типа, хотя я предполагаю, что вы можете использовать auto, чтобы обойти это.

И этот макрос ограничивается выполнением ровно двух переменных. Таким образом, вам нужно будет создать DESTRUCTURE3, DESTRUCTURE4 и т. Д., Чтобы охватить столько, сколько вы захотите.

Мне лично не нравится стиль кода, в котором это заканчивается, но он достаточно близок к некоторым аспектам функции JavaScript.

15

В C++ 17 это называется structured bindings, что позволяет следующее:

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"; 
} 
Смежные вопросы