【问题标题】:constructor of derived class cannot be constexpr if base class contains array member如果基类包含数组成员,则派生类的构造函数不能是 constexpr
【发布时间】:2016-03-09 21:38:15
【问题描述】:

我想定义派生类型 (SBar) 的 constexpr 值,使用其唯一参数是基类 (SFoo) 的变量的构造函数,它只是用于初始化基类。

当基类没有数组成员时,这可以正常工作。但是,当我添加一个数组时,派生值不能再是 constexpr。不过,基类的简单副本确实会产生 constexpr 结果。

为了安全起见,我已明确默认所有复制和移动构造函数。

test.cpp

#define USE_ARRAY


struct SFoo
    {
        constexpr SFoo() =default;
        constexpr SFoo(SFoo const&) =default;
        constexpr SFoo(SFoo      &) =default;
        constexpr SFoo(SFoo     &&) =default;
        constexpr SFoo& operator = (SFoo const&) =default;
        constexpr SFoo& operator = (SFoo      &) =default;
        constexpr SFoo& operator = (SFoo     &&) =default;

#       ifdef USE_ARRAY
            constexpr SFoo(int const (&array)[1]) :
                M_array{array[0]}
                {}

            int M_array[1] = {0};
#       else
            constexpr SFoo(int value) :
                M_value{value}
                {}

            int M_value = 0;
#       endif
    };


struct SBar : SFoo
    {
        constexpr SBar() =default;
        constexpr SBar(SBar const&) =default;
        constexpr SBar(SBar      &) =default;
        constexpr SBar(SBar     &&) =default;
        constexpr SBar& operator = (SBar const&) =default;
        constexpr SBar& operator = (SBar      &) =default;
        constexpr SBar& operator = (SBar     &&) =default;

        constexpr SBar(SFoo foo) : SFoo(foo) {}
    };


// Instances:

#       ifdef USE_ARRAY
    constexpr int arg[1] = {3};
#       else
    constexpr int arg = 3;
#       endif

constexpr SFoo foo(arg); // base "value" constructor is constexpr.
constexpr SFoo foo2(foo); // base copy constructor is constexpr.
constexpr SBar bar(foo); // (line 54): this line fails.

编译

clang++ -std=c++1z -c -o test.o test.cpp 

产量

test.cpp:54:16: error: constexpr variable 'bar' must be initialized by a constant expression
constexpr SBar bar(foo);
               ^~~~~~~~
1 error generated.

但是,如果我不定义 USE_ARRAY,一切正常。

有人知道为什么会这样吗?

(我知道 std::array 可以提供帮助,但我宁愿使用原生数组并了解潜在问题)。

【问题讨论】:

    标签: c++ arrays inheritance constexpr c++17


    【解决方案1】:

    所以对于 clang 来说,似乎有几个修复方法。你可以改变:

    constexpr SBar(SFoo foo) : SFoo(foo) {}
    

    通过常量引用获取foo

    constexpr SBar(const SFoo &info) : SFoo(info) {}
    

    另一个似乎可行的修复方法是注释掉 sFoo 中的以下复制构造函数:

    //constexpr SFoo(SFoo      &) =default;
    

    我没有立即看到 C++1z 标准草案中的语言使这种变化有意义。

    另一方面,gcc 抱怨复制构造函数说隐式定义不会是 constexpr (see it live),例如:

    error: explicitly defaulted function 'constexpr SFoo& SFoo::operator=(const SFoo&)' cannot be declared as constexpr because the implicit declaration is not constexpr
        constexpr SFoo& operator = (SFoo const&) =default;
                        ^
    

    从我对7.1.5 [dcl.constexpr]5.20 [expr.const] 的阅读中,这对我来说并不明显。

    据我阅读第 12.8p26 节可知,隐式定义的复制/移动赋值应该是 constexpr。所以 gcc 在这里似乎不正确。

    【讨论】:

    • 谢谢,解决了。我想知道为什么我不考虑尝试。此外,删除复制分配定义修复了 GCC 问题。无论如何,他们只是在那里帮助调试。
    • @xaxazak 我不能排除这里格式不正确的情况,但我还没有看到。 gcc 的错误好像不对,我还要再挖一些。
    【解决方案2】:

    这不是由于数组成员。这是由于赋值运算符。如果您进行以下更改,代码将适用于 CLANG 和 GCC:

    struct SFoo {
      constexpr SFoo() = default;
      constexpr SFoo(SFoo const&) = default;
      constexpr SFoo(SFoo&&) = default;
      constexpr SFoo(int const (&array)[1]) : M_array{array[0]} {}
    
      int M_array[1] = {0};
    };
    
    struct SBar : SFoo {
      constexpr SBar() = default;
      constexpr SBar(SBar const&) = default;
      constexpr SBar(SBar&&) = default;
      constexpr SBar(SFoo info) : SFoo(info) {}
    };
    

    Live Demo

    如果您使用 std::array 代替经典数组,您之前的设置将起作用:

    struct SFoo {
      constexpr SFoo() = default;
      constexpr SFoo(SFoo const&) = default;
      constexpr SFoo(SFoo      &) = default;
      constexpr SFoo(SFoo     &&) = default;
      constexpr SFoo& operator = (SFoo const&) = default;
      constexpr SFoo& operator = (SFoo      &) = default;
      constexpr SFoo& operator = (SFoo     &&) = default;
      constexpr SFoo(std::array<int, 1> const &array) : M_array{array} {}
    
      std::array<int, 1> M_array = {};
    };
    

    Live Demo

    不知道为什么。我还在找……

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-31
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 2014-01-21
      • 1970-01-01
      • 1970-01-01
      • 2016-07-19
      相关资源
      最近更新 更多