【发布时间】:2014-12-04 20:41:42
【问题描述】:
我有一个带有 constexpr 值构造函数的类,但没有复制或移动 ctor
class C {
public:
constexpr C(int) { }
C(const C&) = delete;
C& operator=(const C&) = delete;
};
int main() {
constexpr C arr[] = {1, 2};
}
我发现这段代码不起作用,因为它实际上是在尝试使用 C 的移动构造函数而不是值构造函数来构造。一个问题是我希望这个对象是不可移动的(出于测试目的),但我想“好吧,好吧,我将添加一个移动构造函数。”
class C {
public:
constexpr C(int) { }
C(const C&) = delete;
C& operator=(const C&) = delete;
C& operator=(C&&) = delete;
C(C&&) { /*something*/ } // added, assume this must be non trivial
};
好的,现在它使用移动构造函数并且一切正常在 gcc 下 但是当我使用 clang 时,它会抱怨因为移动构造函数没有标记constexpr
error: constexpr variable 'arr' must be initialized by a constant expression
constexpr C arr[] = {1, 2};
如果我标记移动构造函数constexpr,它可以在 gcc 和 clang 下工作,但问题是如果移动构造函数完全运行,我希望在移动构造函数中有代码,并且 constexpr 构造函数必须有空体。 (我在 move ctor 中有代码的原因不值得深入探讨)。
那么谁在这里呢?我的倾向是,clang 拒绝代码是正确的。
注意
它确实使用初始化列表和不可复制的不可移动对象进行编译,如下所示:
class C {
public:
constexpr C(int) { }
C(const C&) = delete;
C& operator=(const C&) = delete;
C& operator=(C&&) = delete;
C(C&&) = delete;
};
int main() {
constexpr C arr[] = {{1}, {2}};
}
我主要关心的是上面哪个编译器是正确的。
【问题讨论】:
-
GCC 在启用
-fno-elide-constructors的情况下失败,所以我想它应该也会在启用复制省略的情况下失败,就像 Clang 一样。使用{{1},{2}}复制列表初始化对象,它不调用任何复制ctor,直接调用constexprctor,因此不会出现错误并且两个编译器都是正确的