当前位置: 首页 > 知识库问答 >
问题:

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

钱俊楚
2023-03-14

我一直在编写一组类来允许一个简单的类似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;
}

我一直在使用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;
}

共有1个答案

慕烨烁
2023-03-14

您有一个引用的元组,这意味着引用本身将是const限定的(格式错误,但在本文中被忽略),而不是它引用的值。

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

如果查看std::get是如何定义的,就会看到它返回const std::tuple_元素

实际上,如果您有一个类指针/引用成员,您可以在const限定成员函数(指向/引用的值)中修改它,这是一样的。

 类似资料:
  • 考虑以下代码(演示): 与c-数组副本的结构化绑定由Clang声明为const,非const由GCC声明。 c-array的GCC行为与聚合或类似元组类型的GCC行为一致。 另一方面,从我对标准的阅读来看,我假设Clang遵循所写的内容。在[dcl.struct.bind]/1 e中,类型为cv A,其中A是初始化表达式的类型,cv是结构化绑定声明的cv限定符。初始化表达式的类型相应地为[expr

  • 我正在学习结构化绑定声明。我的理解是,

  • 在该示例中,标识符和之间的相应区别是什么?据我所知,结构绑定中的也有一个引用类型,但是为什么为它指明了一个非引用类型呢?

  • 我在这里找到了最初的*C结构化绑定方案。它提出了一种轻松绑定多个返回值的方法,即: 但现在我看到每个人都指向 现在我学习了“列表是{like,this}编写的”,出现了一种新的列表语法?为什么?这里的花括号有什么问题?

  • 为什么结构化绑定是通过一个唯一命名的变量和所有模糊的“name is bind to”语言定义的? 我个人认为结构化绑定的工作原理如下。给定一个结构: 以下内容: 大致相当于 数组和元组的等价展开式。但显然,这太简单了,而且有所有这些模糊的特殊语言用来描述需要发生的事情。 很明显,我遗漏了一些东西,但确切的情况是什么,一个定义良好的扩展,比如说,折叠表达式,在标准语言中读起来要简单得多? 似乎结构

  • 问题内容: 当我尝试使用var定义变量时,一切正常。 但是将其定义为const不能按预期工作,并且该变量未定义。 我已经在Chrome和Node.js上对其进行了测试。我想念什么吗? 先感谢您! 问题答案: 在 eval 代码中使用 let 和 const 不会调用严格模式。 let 和 const 是 lexicalDeclarations ,将它们的范围限制为封闭的词法范围。 __ __ 词法