13

Is there any formal specification for the layout and memory alignment for the pseudo members of a tuple?

Is there anyway to modify the memory alignment of types in a tuple? Is it effected by a #pragma pack() directive?

For example:

typedef std::tuple<uint8_t, uint32_t> myTuple;

Is there any specification that says this will be in memory the same as:

#pragma pack() // Default packing
struct myStruct
{
    uint8_t first;
    uint32_t second;
}

Apologies if this is a stupid question but I don't entirely understand alignment when it comes to templates.

Edit: Example of what I'm trying to accomplish

Currently I have something along the lines of...

#pragma pack(push)
#pragma pack(4)
struct cTriangle
{
    uint32 Index[3];
};
#pragma pack(pop)

template <class T>
inline bool Read(cFileStream& fStream, std::vector<T>& vec)
{
    if (!vec.size())
        return true;

    // fStream.Read(void* pBuffer, size_t Size)
    // Just a wrapper around a binary ifstream really
    return fStream.Read(&vec[0], sizeof(T) * vec.size());
}

std::vector<cVector3> vPoint;
vPoint.resize(Verticies);
bool result = Read(FileStream, vPoint);

If I wanted to typedef cTriangle as std::tuple<uint32, uint32, uint32> for metaprogramming purposes would I still be able to read/write to the raw memory of the tuple (and thus a vector of tuples) or would that memory have unknown alignment?

ildjarn
  • 59,718
  • 8
  • 115
  • 201
NtscCobalt
  • 1,509
  • 1
  • 14
  • 30
  • 2
    Asking out of curiosity, or is there a problem we can help you solve? – GManNickG Jan 30 '13 at 05:22
  • @GManNickG, I'm actually looking to see if I can use tuple as a replacement for structs and then place them in a vector which I can read and write all at once instead of element by element, tuple argument by tuple argument. I will update the main post to include an example. – NtscCobalt Jan 30 '13 at 16:04

3 Answers3

14

Not only is there no requirement that the objects be arranged any particular way, but many tuple implementations actually put the second object before the first one.

David Schwartz
  • 166,415
  • 16
  • 184
  • 259
  • I'm upvoting as this is useful to know but it doesn't answer the primary part of my question regarding memory layout. – NtscCobalt Jan 30 '13 at 16:14
  • 5
    I thought I answered it. The answer to all three questions is "no". The layout is unspecified and many real-world implementations use a layout that's not even close to what you want. – David Schwartz Jan 30 '13 at 16:20
  • I've added an example of what I'm trying to accomplish. Since you mentioned the order is not specified I can't use tuple in the way I'm currently trying to between compilers but I'd still like to know what the alignment is of the tuple members. – NtscCobalt Jan 30 '13 at 16:27
  • It can be anything. There are no requirements. These aren't the droids you're looking for. – David Schwartz Jan 30 '13 at 16:28
  • Thank you, originally I had marked this as the answer but I decided to mark ecatmur's as it explains the general tuple implementation and why it isn't possible. I figure anyone else who hits this question would get more info out of his answer. If I could mark two I would, sorry. – NtscCobalt Jan 30 '13 at 16:43
13

Tuples are typically not standard-layout, because standard-layout classes can have at most one class in their inheritance hierarchy with non-static data members, and the typical way to implement variadic tuple is through recursive inheritance, with each level of recursion adding one data member. This allows tuple implementations to elide distinct empty members through the empty base class optimisation, which is not available for struct members.

If you check that sizeof(myTuple) == sizeof(myStruct), you are reasonably entitled to assume that the memory layout of the tuple contains the elements of the struct in some (consistent) order, but actually relying on that for aliasing will likely cause undefined behaviour.

If as you say you just want alias with tuple for metaprogramming, you'd be better off using a metaprogramming library such as Boost.Fusion that allows you to annotate the struct type with its members:

#pragma pack(push)
#pragma pack(4)
struct cTriangle {
    uint32 Index[3];
};
#pragma pack(pop)
BOOST_FUSION_ADAPT_STRUCT(
    cTriangle,
    (uint32[3], Index))
ildjarn
  • 59,718
  • 8
  • 115
  • 201
ecatmur
  • 137,771
  • 23
  • 263
  • 343
1

As David points out, there is no guarantee according to the standard. However, if you are interested in a two value tuple, you might want to use std::pair<T1, T2>, which is standard-layout (if T1,T2 are standard-layout) and thus has predictable memory layout.

See also C++0x Tuples Store Elements Backwards

[EDIT]

Sorry, I had not seen ecatmur's answer before answering your comment. By the way: If all members of your struct have the same type, you can of course use std::array, which is standard layout and which allows element access with std::get similar to std::tuple.

Community
  • 1
  • 1
Claas
  • 369
  • 2
  • 5
  • So, why are tuples not standard-layout if all of their template arguments are standard-layout? Is it possible to write a tuple template which does allow standard-layout? – NtscCobalt Jan 30 '13 at 16:16
  • I believe, the reason is that tuples are typically implemented as a recursive inheritance hierarchy. That way a tuple containing N members derives from a tuple with N-1 members plus the type of element N. Thus members are distributed over several derived classes, which violates requirement 5 of the [standard layout](http://en.cppreference.com/w/cpp/types/is_standard_layout) concept. I am not sure if it is possible to implement a tuple, which allows a variable number of members, such that the standard-layout concept is not violated. – Claas Jan 31 '13 at 09:40