【问题标题】:Returning by const value and assigning to a non const variable compiles通过 const 值返回并分配给非 const 变量编译
【发布时间】:2020-11-07 23:52:45
【问题描述】:

我不明白为什么下面的代码允许使用非 const 版本的 foo。我想禁止 const Array 变量提供非 const ArrayView。

#include <iostream>

struct ArrayView
{
    ArrayView() = default;
    ArrayView(const ArrayView&) = delete;
    ArrayView(ArrayView&&) = delete;

    void foo() {std::cout << "non const" << std::endl;}
    void foo() const {std::cout << "const" << std::endl;}
};

struct Array
{
    const ArrayView createView() const
    {
        return {};
    }
};

int main()
{
    const Array arr{};
    auto view = arr.createView();
    view.foo();

    return 0;
}

输出:

non const

我在 Windows 10 上安装了 gcc 10.1.0。

【问题讨论】:

    标签: c++ c++11 constants return-value auto


    【解决方案1】:

    auto的类型推导规则与模板参数推导相同; view 被声明为非引用,createView 的返回值的 const 部分被忽略。结果view 的类型是ArrayView,而不是const ArrayView

    另一方面,如果您直接在返回值上调用foo,则会选择const 版本。例如

    arr.createView().foo();
    

    作为解决方法,您可以将view 明确声明为const

    const auto view = arr.createView();
    

    或者声明view作为参考。

    auto& view = arr.createView(); // the type of view is const ArrayView&
    

    PS:我注意到您将ArrayView 的复制/移动构造函数都标记为delete。由于auto view = arr.createView(); 中的C++17,它们将因为mandatory copy elision 而被完全省略,它们在这里是否可用并不重要。

    【讨论】:

    • 感谢您的回答。为什么返回值的 const 部分被值忽略而不是引用?
    • @Cevik view 不必是 const。例如,给定const int i1 = 42;,那么int i2 = i1; 就可以了。 i2 不必是 const,因为 i1 是; i2 是从i1 复制而来的独立对象。因此,如果您希望它是 const,您必须明确指定。作为参考,那么它必须是const。例如必须是const int&amp; i2 = i1;int&amp; i2 = i1;无效。
    • 这很有趣。我认为这仅适用于没有显式复制构造函数的 POD 类型,但为此我在 ArrayView 中删除了它们。未经我同意,似乎制作了一个“精神上的副本”来删除这个常量。
    • @Cevik 对于非类类型和类类型,这里的规则保持不变。
    • 谢谢,我想我会引入一个 IsConst 模板参数,以确保无论客户使用 auto 做什么。我无法在我的真实代码中生成左值引用;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-05
    • 1970-01-01
    • 2011-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-12
    相关资源
    最近更新 更多