Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

const decltype(*std::begin(container))& val doesn't make val const?

This piece of code:

std::vector <int> ints(5,1);
std::for_each(ints.begin(), ints.end(), [](const decltype(*std::begin(ints))& val){ val*=2; });

compiles and runs just fine in Visual Studio 2010, and modifies every value in the container like if the const keyword weren't there. Is this a bug in the compiler, as the expected behaviour is that val is non-modifiable? (in other words, I expect it not to compile, but it does)

Update:

std::for_each(ints.begin(), ints.end(), [](const std::remove_reference<decltype(*std::begin(ints))>::type& val){ val*=2; });

seems to behave const-correctly, however that doesn't make me smarter.

Note:

decltype(*std::begin(ints)) is a reference to an int.

like image 860
Viktor Sehr Avatar asked Feb 23 '23 09:02

Viktor Sehr


1 Answers

It seems the compiler tries to apply the const to the int&, making it int& const, which is superfluous as a reference can't be reseated anyways1). Try putting the const between the decltype and the reference: decltype(*ints.begin()) const&

1) Thanks for the comments for the clarification.

Scrap that, thanks to @Ben's comment I noticed the real problem. Try decltype(*ints.cbegin()). cbegin returns a const_iterator, which dereferences to a reference-to-const. Also, no need for the extra ampersand, as *ints.cbegin() already returns a int const&.

To explain what went wrong in the OP's code, it's just as @Ben Voigt says in the comments: decltype(*std::begin(ints)) resolves to int&, since std::begin(ints) returns a non-const iterator for non-const containers and dereferencing such an iterator returns a reference-to-non-const.

like image 141
Xeo Avatar answered Mar 01 '23 23:03

Xeo