Variables marked as const using structured bindings are not const

坚强是说给别人听的谎言 提交于 2019-12-18 10:58:20

问题


I have been writing a set of classes to allow for a simple python-like zip-function. The following snippet works (almost) just as expected. However, the two variables a and b are not 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;
}

I have been using gcc 7.3.0. Here is the 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;
}

回答1:


You have a tuple of a reference, which means that the reference itself will be const qualified (which is ill-formed but in this context ignored), not the value referenced by it.

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

If you look how std::get is defined, you'll see that it returns const std::tuple_element<0, std::tuple<int&>>& for the structured binding above. As the first tuple element is a reference, the const& has no effect, and thus you can modify the return value.

Really, it's same thing if you have a class pointer/reference member that you can modify in a const qualified member function (the value pointed/referenced that is).



来源:https://stackoverflow.com/questions/49308674/variables-marked-as-const-using-structured-bindings-are-not-const

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!