11

Say I want to store three types in a tuple : int, float and std::vector<double>

If I leave aside matters of subsequent interface, does this

tuple<int, float, vector<int>> t;

have any differences from this

tuple<vector<int>, int, float> t;

Due to the implementation of tuple as a class of variadic bases, I'm expecting a different layout for the produced classes, but does it matter in any way ? Also are there any optimization considerations to take into account, when placing types in a tuple (eg put the largest first etc) ?

pmr
  • 58,701
  • 10
  • 113
  • 156
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
  • I don't believe the standard imposes anything on the order in which the objects are stored in a tuple, so you need to check with your platforms docs. – Mat May 28 '14 at 11:22
  • out of curiosity, why are you not using a vector of `struct T` instead of this ? What is the advantage that you are getting ? – user2485710 May 28 '14 at 11:30
  • 5
    @user2485710: That's a completely different thing... – Lightness Races in Orbit May 28 '14 at 11:33
  • @LightnessRacesinOrbit I know, but the OP is not describing an use case, I was curious about the reason why doing this. – user2485710 May 28 '14 at 11:37
  • 6
    Why is the OP not using a map of strings to std::chrono::milliseconds? What is the advantage? – R. Martinho Fernandes May 28 '14 at 11:38
  • `vector` is not really "large". It only takes around three native integers. – Danvil May 28 '14 at 12:00
  • 1
    @R.MartinhoFernandes I think the OP should use jQuery. There's no advantage in avoiding it. – Lightness Races in Orbit May 28 '14 at 12:00
  • 1
    @LightnessRacesinOrbit He should use a chisel and manually engrave all the pixels on his monitor. – Danvil May 28 '14 at 12:02
  • @Danvil: An excellent idea! – Lightness Races in Orbit May 28 '14 at 12:03
  • 2
    The order may be very important from the performance point of view. Tuples are compared from first to last component. Thus, for example, if a tuple is used as a map key and the types of which it is composed have different comparison complexities, it is more profitable to put the 'lightweight' types first, and 'bulky' types last. – ach May 28 '14 at 17:04
  • "*Due to the implementation of `tuple` as a class of variadic bases*" This is an implementation detail, and one that isn't necessarily true. libc++, for example, does not use recursive bases as libstdc++ does. @AndreyChernyakhovskiy : An excellent point, I hope more people see it. – ildjarn May 29 '14 at 00:38

3 Answers3

15

The standard doesn't place any restrictions on the actual layout of the types. The only things the order influences are the results of std::get<N>, std::tuple_element<N, T> and so on.

I know that libstdc++ and Visual C++ lay out the types in reverse order of the order given; libc++ lays out the types in the order given. This essentially means that there is no portable way to pick an order that always produces the best layout.

Other orders are possible, though. An implementation is allowed to implement tuple with a layout that always produces minimal size but still preserves the same semantics for std::get<N> and so on. I don't know of any standard library implementation that does this, though.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • What I'm doing (as a spare time exercise) is to make a metaprogramm that would "fix" the tuple layout and produce an optimal type. Up to now I was supposing putting the smallest type first (eg that's a [related question](http://stackoverflow.com/q/23895981/2567683) on this) is the way to go. Do you have any suggestions on the ordering? – Nikos Athanasiou May 28 '14 at 11:54
  • 2
    @NikosAthanasiou if you follow the link in my answer you will see that I have documented my own adventure in doing that exercise and you can probably find answers to all your doubts there :) Well, except `tuple_cat` which I haven't yet taken the time to describe (it's damn messy). The size of the types is not really important for optimal layout; alignment is. You should make it so that the types are physically stored in decreasing order of alignment. – R. Martinho Fernandes May 28 '14 at 11:58
  • 4
    @NikosAthanasiou well there are only N! different arrangements of types. Write a metaprogram that finds the smallest resulting `std::tuple` from those N! different arrangements and compares it against your choice, and `static_assert`s your choice is smallest. Then you'll get an error message at least. (Note: does not work well for large N) – Yakk - Adam Nevraumont May 28 '14 at 15:08
  • 3
    @Yakk "only N!" - Now _there's_ something you don't hear every day! – Stuart Olsen May 29 '14 at 05:43
1

The standard does not specify an implementation for std::tuple. However it guarantees that std::tuple<A,B,C> shall be a different type than for example std::tuple<B,A,C>. std::tuple is an ordered list of types.

boost::fusion provides a data type for a set style container of types, for cases where the order is not important: boost::fusion::set<>

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Danvil
  • 22,240
  • 19
  • 65
  • 88
0

The standard does not specify how a tuple should be implemented and it is entirely possible that an implementation reorders the arguments to produce a better layout while preserving the semantics of std::get<int N>. However, I do not know of any implementation that actually does this since arranging a set of types in a order that produces a good layout is difficult.

It is likely that a different order of arguments is going to produce a different layout. If this matters depends on your use-case. If you want to optimize here you should consider size constraints (additional padding) and cache line size of your target architecture.

pmr
  • 58,701
  • 10
  • 113
  • 156