如果基类包含数组成员,则派生类的构造函数不能是constexpr
constructor of derived class cannot be constexpr if base class contains array member
我想定义派生类型(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会有所帮助,但我更愿意使用本机数组并了解潜在的问题)。
因此,对于clang,似乎有几个修复方法。您可以更改:
constexpr SBar(SFoo foo) : SFoo(foo) {}
通过常量引用获取foo
:
constexpr SBar(const SFoo &info) : SFoo(info) {}
另一个似乎有效的修复方法是注释掉sFoo中的以下副本构造函数:
//constexpr SFoo(SFoo &) =default;
我没有立即看到C++1z标准草案中的语言使这一改变有意义。
另一方面,gcc抱怨复制构造函数说隐式定义不是constexpr(请参阅它的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
[Epr.const]时并不明显
根据我对12.8p26节的阅读,隐式定义的复制/移动赋值应该是constexpr。所以gcc在这里似乎不正确。
这不是因为数组成员。这是由于赋值运算符。如果您进行以下更改,代码将同时适用于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) {}
};
实时演示
如果您使用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 = {};
};
实时演示
没有原因。我还在找。。。
相关文章:
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 为什么虚函数不能是静态的和全局的?
- 仅包含可移动 std::map 的类的移动构造函数不起作用
- C++ - 空模板类构造函数不初始化值
- 为什么从另一个构造函数内部调用C++构造函数不修改类变量?
- 将参数传递给泛型 lambda 时复制构造函数不正确
- 为什么复制构造函数不需要检查输入对象是否指向自身?
- 为什么继承的受保护构造函数不能公开?
- 如果普通默认构造函数不执行任何操作,为什么我们不能使用 malloc 创建平凡可构造的对象?
- 构造函数不能用于启发性化
- 有没有办法使成员函数不能从构造函数调用
- "Framework::Graphics::Material"的默认构造函数不能被引用 - 它是一个已删除的函数
- 琐碎的默认构造函数不能是 constexpr?
- 如果基类包含数组成员,则派生类的构造函数不能是constexpr
- 为什么构造函数不能在 c++ 中声明为静态?
- 构造函数不能是虚函数
- 语句调用构造函数,但对构造函数不做任何操作——为什么它不能编译
- 构造函数不能从抽象类创建对象
- c++工厂.子构造函数不能从父构造函数访问
- 为什么构造函数不能优雅地处理错误?