How can I emulate destructuring in C++?
Asked Answered
C

4

78

In JavaScript ES6, there is a language feature known as destructuring. It exists across many other languages as well.

In JavaScript ES6, it looks like this:

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

//Destructuring
var {species, sound} = animal

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

What can I do in C++ to get a similar syntax and emulate this kind of functionality?

Cube answered 13/7, 2015 at 22:22 Comment(6)
In C++ you can overload operators. If you define a structure and overload its assignment operator accordingly, maybe you can achieve what you are aiming for. Not sure thought. But you could maybe research into that direction.Dissimilation
Python and Ruby also allows assignment to tuples, but I think this Object destructuring syntax is pretty unique to JS...Hurley
@Karoly: I don't think the syntax is particularly unique; if this is doing what it looks like, C++ essentially already has this in the form of using statements. The novel bit is the extension to allow import members of objects as well as members of namespaces. e.g. if someone said using animal.species; was in c++1z, what do you think it would do?Counteroffensive
@Hurkyl: this isn't like using. It's a new variable declaration.Hurley
Finally this is possible in C++17.Hix
@AppajiChintimi it is not. Structured bindings are index based. Destructuring is name based.Dusty
P
58

For the specific case of std::tuple (or std::pair) objects, C++ offers the std::tie function which looks similar:

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;

I am not aware of an approach to the notation exactly as you present it.

Prudery answered 13/7, 2015 at 22:39 Comment(9)
You can add make_tie to animal that returns a tie.Ideality
The notation is not important. Only the semantics. To be fair, the javascript notation looks a bit weird for destructuring. Most languages use either just the comma operator: x, y = z or braces (x,y) = zTabular
@Tabular The JS example destructures an object's properties. Simply using the usual comma-separated would be undefined, seeing object keys have no order.Pluvious
@Kroltan: It depends on the language. In some languages the comma operator is the destructuring operator. What's "usual" in some languages may not be in others.Tabular
@Tabular But the point is, Javascript has both notations, only the comma (with square brackets) is for array elements and the {} delimited is for object properties. [a,b] = [1,2], {a,b}={a:"hello", b:12}. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Pluvious
@Kroltan: No, that's not the point at all... sigh.. the point is, Escualo is worried that his approach may not meet the OPs requirement because the syntax is different form javascript but syntax is not important because languages other than javascript use syntax different from javascript for destructuring.Tabular
@Tabular ...Which extends to the fact that the OP desires to destructure objects, not lists/tuples.Pluvious
I admit, my question was a bit open-ended in terms of desired syntax and ease of use. Regardless, destructing is a language concept, and I was curious how that concept could be emulated in a language that does not explicitly have it. I expected varying results and leaving it up to the readers what would be best for their given situation.Cube
For std::tuple, there's a proposal offering something similar to auto {x, y, z} = some_tuple; syntax. It seems to be progressing decently well.Audwin
G
150

In C++17 this is called structured bindings, which allows for the following:

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";
}
Gymkhana answered 1/12, 2016 at 15:10 Comment(5)
I believe this is the most up to date and relevant answer.Chaldea
Is there anything equivalent to std::ignore when we don't want to destructure everything?Fie
Just a warning that this is not quite equivalent to the JavaScript version. If you swap weight and sound in the assignment list so [ species, sound, weight ] = ..., it prints weight="woof" and sound=23.Christchurch
@Christchurch I agree it is similar to the array destructuring in Javascript (which is index based) and not the object destructuring in Javascript (which is name based).Gymkhana
I’d use const auto&.Errhine
P
58

For the specific case of std::tuple (or std::pair) objects, C++ offers the std::tie function which looks similar:

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;

I am not aware of an approach to the notation exactly as you present it.

Prudery answered 13/7, 2015 at 22:39 Comment(9)
You can add make_tie to animal that returns a tie.Ideality
The notation is not important. Only the semantics. To be fair, the javascript notation looks a bit weird for destructuring. Most languages use either just the comma operator: x, y = z or braces (x,y) = zTabular
@Tabular The JS example destructures an object's properties. Simply using the usual comma-separated would be undefined, seeing object keys have no order.Pluvious
@Kroltan: It depends on the language. In some languages the comma operator is the destructuring operator. What's "usual" in some languages may not be in others.Tabular
@Tabular But the point is, Javascript has both notations, only the comma (with square brackets) is for array elements and the {} delimited is for object properties. [a,b] = [1,2], {a,b}={a:"hello", b:12}. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Pluvious
@Kroltan: No, that's not the point at all... sigh.. the point is, Escualo is worried that his approach may not meet the OPs requirement because the syntax is different form javascript but syntax is not important because languages other than javascript use syntax different from javascript for destructuring.Tabular
@Tabular ...Which extends to the fact that the OP desires to destructure objects, not lists/tuples.Pluvious
I admit, my question was a bit open-ended in terms of desired syntax and ease of use. Regardless, destructing is a language concept, and I was curious how that concept could be emulated in a language that does not explicitly have it. I expected varying results and leaving it up to the readers what would be best for their given situation.Cube
For std::tuple, there's a proposal offering something similar to auto {x, y, z} = some_tuple; syntax. It seems to be progressing decently well.Audwin
E
5

Mostly there with std::map and 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;
}
Eliathas answered 13/7, 2015 at 22:39 Comment(0)
F
1

Another possibility could be done as

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

which would be used like:

struct Example
{
    int foo;
    int bar;
};

Example testObject;

int DESTRUCTURE2(foo, bar, testObject);

yielding local variables of foo and bar.

Of course it's limited to creating variables all of the same type, although I suppose you could use auto to get around that.

And that macro is limited to doing exactly two variables. So you would have to create DESTRUCTURE3, DESTRUCTURE4, and so on to cover as many as you want.

I don't personally like the code style this ends up with, but it comes reasonably close to some of the aspects of the JavaScript feature.

Firetrap answered 14/7, 2015 at 0:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.