3

I have defined a (const) tuple as follows:

double var1, var2;
const tuple<double&, double&> my_tup(var1, var2);

Now, why am I able to do the following:

get<0>(my_tup) = 3215.513

The above code would only make sense if the references contained in the tuple are const pointers to var1 and var2 - the memory address itself is const (because the tuple is const, so we cannot change any of its contents), but the contents of the memory addresses pointed to, not, hence the allowed change. But, if you look at this discussion about what references really are, you will see there are some fervent advocates for the reference not being a const pointer, but just a different name for a variable already declared. In that case, how can I interpret a const tuple of references? Is declaring the tuple as const above, if it contains references, pointless then?

(Note that I had to use a const tuple in another setting, which is too complicated to explain and irrelevant to the question.)

Community
  • 1
  • 1
Konrad
  • 2,207
  • 4
  • 20
  • 31
  • 1
    I may be remembering incorrectly, but tuples might be required to use `std::reference_wrapper` for reference-typed elements, in which case the elements would be const pointers to non-const. – chris Oct 06 '15 at 01:07
  • 1
    Ah, what I was thinking of was `make_tuple`, where giving it a `reference_wrapper` (e.g., from `ref` or `cref`) will deduce a reference type. – chris Oct 06 '15 at 01:20

1 Answers1

4

If a class object is const, then its data members are implicitly const too (unless declared mutable). So, in general, if a tuple is const, then none of its members can be modified.

However, a reference cannot be const (only the referenced type can be). Indeed, a reference itself cannot be modified anyway (any attempt to do so modifies the object referred to). Since a reference cannot be const, the members of your const tuple still have type double&, not const double&, and the const on your tuple is pretty meaningless in this case. What you really want is tuple<const double&, const double&>.

Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • Ok, so it is pointless to declare a tuple as const then. It was actually from this discussion [Inline Link](http://stackoverflow.com/questions/17982214/decltype-of-boostmake-zip-iterator) that I got the example. If you look at the boost::tuple argument to the lambda function (within the for_each function) in the answer to the OP's question, you will see the tuple is declared `const`. It does not compile otherwise, leaving me to think that the boost::zip_iterator returns a `const` tuple when dereferenced. – Konrad Oct 06 '15 at 01:24
  • But in any case, I actually want to be able to modify the contents of the tuple (actually, the stuff that the references point to) so I will keep the template arguments to the tuple as is. – Konrad Oct 06 '15 at 01:26
  • 1
    @KonradKapp I assume the lambda takes a const reference because that's a very common idiom in C++, not because another function returns a `const` object by value (which is very rare, as far as I know) – Brian Bi Oct 06 '15 at 01:28
  • so, if I have a `const tuple`, then the reason I cannot modify its members is not because the member types are now `const int` by implication, but because it prohibits me from modifying members by its own mechanism? In other words, members are still of type `int` in the example above, but the tuple still disallows me to modify? Actually I've noticed you get a different error message when trying to modify `const tuple` members from the usual messages received when modifying `const`, so that's probably why. – Konrad Oct 06 '15 at 01:33
  • In addendum to my comment above, the `const tuple` disallows me from changing what the reference "points to" (for lack of a better term), but it cannot change what it points to anyway, hence the pointless effort? Also, with regards to what you mentioned on lambda taking a `const` reference, how can it still take a `const` reference, if I explicitly defined the argument to the lambda to not be a `const` reference (in the case that it did not compile)? – Konrad Oct 06 '15 at 01:37
  • 1
    @KonradKapp If you have `const tuple` then the members implicitly have type `const int`, so that's why you can't modify them. The tuple doesn't have a special mechanism to prevent it. – Brian Bi Oct 06 '15 at 01:39
  • 1
    @KonradKapp Regarding references, you are basically correct: you can't reseat a reference under any circumstances. As for your other question, I don't understand. If you write a function taking a non-`const` reference, it will not accept an argument that is a `const` reference. – Brian Bi Oct 06 '15 at 01:41
  • ok, but it beats me then why the `const tuple` members do not have type `const double &` (instead of `double & const`, as I understand from your original answer). With regards to the lambda I mentioned earlier, sorry, my wording was a bit bad there: You mentioned earlier that you assume that the lambda takes a const reference, but the whole reason I had to work with a `const tuple` here, was that when I defined my lambda to take a non-`const` reference, it did not compile. (continued in next comment) – Konrad Oct 06 '15 at 01:47
  • It only compiled when it was declared `const`, which led me to think that the iterator returned by boost::make_zip_iterator, returns `const` references, when dereferenced, because the lambda function only wanted to accept `const` references. – Konrad Oct 06 '15 at 01:49
  • In any case, my apologies for my lengthy questions and ruthless interrogation. Haha I am quite eager to learn the nitty gritty things of the language when I can, so thank you for you patience. – Konrad Oct 06 '15 at 01:51
  • @Brain, also, my apologies for the `double & const` thing I posted in the comment above, could not change the comment after 5 minutes...will just delete it later...but by it I meant the non-existing `const` reference as you put it in you original answer – Konrad Oct 06 '15 at 02:03
  • @Brain, if you are still reading this, I have found a description of the `zip_iterator` class, and I am assuming that `get_iterator_tuple()` is the function that gets called when "dereferencing" the iterator in the for_each loop. The `get_iterator_tuple()` is indeed declared as returning a `const IteratorTuple&`, explaining why the lambda function had to be declared with a `const` parameter (if I am correct). – Konrad Oct 06 '15 at 02:29
  • @Brain, if you are interested, the description of the `zip_iterator` class is [here](http://www.boost.org/doc/libs/1_41_0/libs/iterator/doc/zip_iterator.html). – Konrad Oct 06 '15 at 02:30
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/91438/discussion-between-brian-and-konrad-kapp). – Brian Bi Oct 06 '15 at 03:17