6

After a bit of investigation, I found that C++0x stores the elements in a tuple backwards in memory.

For example, take this code:

std::tuple<char, char, char> x('\0', 'b', 'a');
char* y = (char*)&x;
std::cout << sizeof(x) << std::endl;
std::cout << y << std::endl;

When compiled with the GCC 4.5.2, I get the following output:

3
ab

This initially puzzled me. Why is the data stored backwards? After hunting through GNU's unintentionally obfuscated headers, I noticed that the implementation was similar to this:

template<typename head, typename... tail> class tuple<head, tail...> : public tuple<tail...>
{
  head value;
  ...
};

Because the base class contains the last element, then the next derived class contains the second to last, etc., the actual order of the template arguments is reversed.

When I first got into tuples, I thought that I could use them for a function like glInterleavedArrays(), which sets an array of vertex data as tuples of colors, texture coordinates, normals, and points. Of course, if I make an array of tuples, this data will have to be inputted in reverse, which can result in really weird bugs if you happen to forget to put the arguments in the right order.

What about something like this, then?

template<typename... head, typename tail> class tuple<head..., tail> : public tuple<head...>
{
  tail value;
  ...
};

Under the GCC 4.5.2:

error: parameter pack argument ‘head ...’ must be at the end of the template argument list

Unless this becomes available in the future, I'm pretty much stuck on finding another way to implement this. Is there another way? Some way to trick the GCC into getting a properly-ordered tuple memory-wise?

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
RétroX
  • 1,996
  • 4
  • 16
  • 24

2 Answers2

8

The tuple layout that you are exploring is an unspecified implementation detail of tuple. Other implementations will have other layouts. If you write to this one, depending on gcc's layout, your code may not be portable to other std::libs.

The libc++ tuple implementation (for example) has the opposite (in-order) layout.

Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
6

Why do you care what the implementation of tuple is? Program to an interface, not an implementation.

If you only use tuple via its advertised interface, then you will get your objects out in the same order you put them in. If you instead break encapsulation by accessing its contents directly, for example by the dodgy pointer cast in your example, then all bets are off.

Community
  • 1
  • 1
Philip Potter
  • 8,975
  • 2
  • 37
  • 47
  • I already stated why - `glInterleavedArrays()` is a function which requests an interleaved data array. My intent was to create a tuple class which would operate upon this principle - interleaving data in an array of tuples so that I could pass the data to GL. If you want more info, see the OpenGL documentation: http://www.opengl.org/sdk/docs/man/xhtml/glInterleavedArrays.xml – RétroX Mar 05 '11 at 21:22
  • @RetroX: then rather than relying on the implementation of tuple, you want an object whose interface provides a means of serialization in a known order. Either way, you want the interface to provide the guarantee, so that you are not tied to implementation details. – Philip Potter Mar 05 '11 at 21:51
  • @PhilipPotter: `std::array` being the obvious candidate here if the types are homogeneous, since it otherwise shares the same basic features of `std::tuple` (size fixed at compile-time, essentially zero overhead), and implicitly guarantees the values are stored in order (because `data` returns a raw pointer, and guarantees that the range `[data(); data() + size())` is a valid range, and that for non-empty arrays, the pointer is the address of the first element). Failing that, you'd go with a simple POD struct (which would let you set packing as needed in most compilers). – ShadowRanger Sep 13 '19 at 17:38