使用结构化绑定标记为const的变量不是const

Jon*_*nas 19 c++ const c++17 structured-bindings

我一直在编写一组类来允许一个简单的类似python的zip函数.以下代码片段(几乎)可以正常工作.然而,这两个变量ab没有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;
}
Run Code Online (Sandbox Code Playgroud)

我一直在使用gcc 7.3.0.这是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;
}
Run Code Online (Sandbox Code Playgroud)

Rak*_*111 16

你有一个引用的元组,这意味着引用本身将被const限定(这是不正确的,但在此上下文中被忽略),而不是它引用的值.

int a = 7;
std::tuple<int&> tuple = a;
const auto&[aa] = tuple;
aa = 9; // ok
Run Code Online (Sandbox Code Playgroud)

如果您看看如何std::get定义,您将看到它返回const std::tuple_element<0, std::tuple<int&>>&上面的结构化绑定.由于第一个元组元素是引用,const&因此无效,因此您可以修改返回值.

实际上,如果你有一个类指针/引用成员,你可以在一个const合格的成员函数(指向/引用的值)中修改它是一回事.

  • @SergeyA我的意思是`int&const`,引用是const (3认同)
  • 我根本不关注你的解释.你是什​​么意思`,这意味着引用本身将是const限定的,而不是它引用的值.?引用只是对象的另一个名称.对它的任何操作都是对它所绑定的对象的操作.我无法理解"参考本身"的含义. (2认同)
  • 完全是@WF,这就是忽略const的原因http://eel.is/c++draft/dcl.meaning#dcl.ref-1.sentence-3 (2认同)
  • @Zebrafish除了冗余之外,没有理由不允许使用`int&const`.所以我们不能这样写.但这就是语法将其与结构化绑定放在一起的地方.就像你有`std :: tuple <int*>`一样 (2认同)
  • 那么如何提供带有标识符的结构化绑定,该标识符将无法修改底层*非常量*引用的左值? (2认同)