c++ - Las variables marcadas como const que usan enlaces estructurados no son constantes
c++17 structured-bindings (1)
Tiene una tupla de una referencia, lo que significa que la referencia en sí estará const
(que está mal formada pero en este contexto se ignored ), no el valor al que hace referencia.
int a = 7;
std::tuple<int&> tuple = a;
const auto&[aa] = tuple;
aa = 9; // ok
Si observa cómo se define std::get
, verá que devuelve const std::tuple_element<0, std::tuple<int&>>&
para el enlace estructurado anterior. Como el primer elemento de la tupla es una referencia, const&
no tiene ningún efecto, por lo que puede modificar el valor de retorno.
Realmente, es lo mismo si tiene un puntero de clase / miembro de referencia que puede modificar en una función miembro calificada const
(el valor señalado / referenciado).
He estado escribiendo un conjunto de clases para permitir una simple función zip
parecida a python. El siguiente fragmento de código funciona (casi) como se esperaba. Sin embargo, las dos variables a
y b
no son const
.
std::vector<double> v1{0.0, 1.1, 2.2, 3.3};
std::vector<int> 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;
}
He estado utilizando gcc 7.3.0. Aquí está el MCVE:
#include <iostream>
#include <tuple>
#include <vector>
template <class ... Ts>
class zip_iterator
{
using value_iterator_type = std::tuple<decltype( std::begin(std::declval<Ts>()))...>;
using value_type = std::tuple<decltype(*std::begin(std::declval<Ts>()))...>;
using Indices = std::make_index_sequence<sizeof...(Ts)>;
value_iterator_type i;
template <std::size_t ... I>
value_type dereference(std::index_sequence<I...>)
{
return value_type{*std::get<I>(i) ...};
}
public:
zip_iterator(value_iterator_type it) : i(it) {}
value_type operator*()
{
return dereference(Indices{});
}
};
template <class ... Ts>
class zipper
{
using Indices = std::make_index_sequence<sizeof...(Ts)>;
std::tuple<Ts& ...> values;
template <std::size_t ... I>
zip_iterator<Ts& ...> beginner(std::index_sequence<I...>)
{
return std::make_tuple(std::begin(std::get<I>(values)) ...);
}
public:
zipper(Ts& ... args) : values{args...} {}
zip_iterator<Ts& ...> begin()
{
return beginner(Indices{});
}
};
template <class ... Ts>
zipper<Ts& ...> zip(Ts& ... args)
{
return {args...};
}
int main()
{
std::vector<double> 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;
}