Can one element of a tuple reference another?
c++, c++11, tuples, undefined-behavior
Solution
This works for me:
#include <tuple>
#include <iostream>
int main()
{
std::tuple<int&, int> t(std::get<1>(t), 2);
std::cout << std::get<0>(t) << '\n';
std::get<1>(t) = 3;
std::cout << std::get<0>(t) << '\n';
}
Update
I just asked about this case on the CWG mailing list. Mike Miller assures me that this is undefined behavior per 3.8p6 bullet 2:
... The program has undefined behavior if:
...
- the glvalue is used to access a non-static data member or call a non-static member function of the object, or
...
It would be well defined behavior if `tuple` was an aggregate, but because `tuple` has a user-declared constructor, 3.8p6b2 applies.
However this works, and avoids UB:
#include <tuple>
#include <functional>
#include <cassert>
int main()
{
int dummy;
std::tuple<std::reference_wrapper<int>, int> t(dummy, 2);
std::get<0>(t) = std::get<1>(t);
assert(std::get<0>(t) == 2);
std::get<1>(t) = 3;
assert(std::get<0>(t) == 3);
}
Problem
Update: See the full answer below. The short answer is no, not directly. You can create an indirect reference using `std::reference_wrapper` or accomplish the same effect more generally with pointers (but without the syntactic sugar and added safety of references). I ask because tuples make a convenient variadic storage unit in C++11. In theory it sounds reasonable for one element of a tuple to hold a reference to another element in the same tuple. (Replace "reference" with "pointer" and it works in practice.) The devil is the details of constructing such a tuple. Consider the following example: ``` #include <tuple> #include <iostream> class A { public: A() : val(42) { } int val; }; class B { public: B(A &a) : _a(a) { } int val() { return _a.val; } private: A &_a; }; int main() { A a; B b(a); std::tuple<A, B> t1(a, b); a.val = 24; std::cout << std::get<0>(t1).val << "\n"; // 42 std::cout << std::get<1>(t1).val() << "\n"; // 24 return 0; } ``` The second element in the tuple `t1` references the automatic variable `a` instead of the first element in `t1`. Is there any way to construct a tuple such that one element of the tuple could hold a reference to another element in the same tuple? I'm aware that you could sort of achieve this result by creating a tuple of references, like this: ``` int main() { A a; B b(a); std::tuple<A &, B &> t2 = std::tie(a, b); a.val = 24; std::cout << std::get<0>(t2).val << "\n"; // 24 std::cout << std::get<1>(t2).val() << "\n"; // 24 return 0; } ``` But for my purposes that's cheating, since the second element in `t2` is still ultimately referencing an object that lives outside of the tuple. The only way I can think of doing it compiles fine but may contain undefined behavior [Edited to reflect more concise example provided by Howard Hinnant]: ``` int main() { std::tuple<A, B> t3( A(), B(std::get<0>(t3)) ); // undefined behavior? std::get<0>(t3).val = 24; std::cout << std::get<0>(t3).val << "\n"; std::cout << std::get<1>(t3).val() << "\n"; // nasal demons? } ``` Edit: Here is a minimal test program that returns with a non-zero exit status when compiled using g++ 4.7 with -O2 or higher. This suggests either undefined behavior or a bug in gcc. ``` #include <tuple> class Level1 { public: Level1() : _touched(false), _val(0) { } void touch() { _touched = true; } double feel() { if ( _touched ) { _touched = false; _val = 42; } return _val; } private: bool _touched; double _val; }; class Level2 { public: Level2(Level1 &level1) : _level1(level1) { } double feel() { return _level1.feel(); } private: int _spaceholder1; double _spaceholder2; Level1 &_level1; }; class Level3 { public: Level3(Level2 &level2) : _level2(level2) { } double feel() { return _level2.feel(); } private: Level2 &_level2; }; int main() { std::tuple<Level3, Level2, Level1> levels( Level3(std::get<1>(levels)), Level2(std::get<2>(levels)), Level1() ); std::get<2>(levels).touch(); return ! ( std::get<0>(levels).feel() > 0 ); } ```