Les variables marquées comme const à l’aide de liaisons structurées ne sont pas constantes

J’ai écrit un ensemble de classes pour permettre une fonction zip simple, de type python. L’extrait suivant fonctionne (presque) exactement comme prévu. Cependant, les deux variables a et b ne sont pas const .

 std::vector v1{0.0, 1.1, 2.2, 3.3}; std::vector v2{0, 1, 2}; for (auto const& [a, b] : zip(v1, v2)) { std::cout << a << '\t' << b << std::endl; a = 3; // I expected this to give a compiler error, but it does not std::cout << a << '\t' << b << std::endl; } 

J’ai utilisé gcc 7.3.0. Voici le MCVE:

 #include  #include  #include  template  class zip_iterator { using value_iterator_type = std::tuple<decltype( std::begin(std::declval()))...>; using value_type = std::tuple<decltype(*std::begin(std::declval()))...>; using Indices = std::make_index_sequence; value_iterator_type i; template  value_type dereference(std::index_sequence) { return value_type{*std::get(i) ...}; } public: zip_iterator(value_iterator_type it) : i(it) {} value_type operator*() { return dereference(Indices{}); } }; template  class zipper { using Indices = std::make_index_sequence; std::tuple values; template  zip_iterator beginner(std::index_sequence) { return std::make_tuple(std::begin(std::get(values)) ...); } public: zipper(Ts& ... args) : values{args...} {} zip_iterator begin() { return beginner(Indices{}); } }; template  zipper zip(Ts& ... args) { return {args...}; } int main() { std::vector v{1}; auto const& [a] = *zip(v).begin(); std::cout << a << std::endl; a = 2; // I expected this to give a compiler error, but it does not std::cout << a << std::endl; } 

Vous avez un tuple de référence, ce qui signifie que la référence elle-même sera qualifiée de const (ce qui est mal formé mais ignorée dans ce contexte), pas la valeur référencée par celle-ci.

 int a = 7; std::tuple tuple = a; const auto&[aa] = tuple; aa = 9; // ok 

Si vous regardez comment std::get est défini, vous verrez qu’il renvoie const std::tuple_element<0, std::tuple>& pour la liaison structurée ci-dessus. Comme le premier tuple est une référence, const& n’a aucun effet et vous pouvez donc modifier la valeur de retour.

En réalité, c’est la même chose si vous avez un pointeur de classe / un membre de référence que vous pouvez modifier dans une fonction de membre qualifié const (la valeur pointée / référencée).