对于此结构:
struct Wrapper {
int value;
constexpr explicit Wrapper(int v) noexcept : value(v) {}
Wrapper(const Wrapper& that) noexcept : value(that.value) {}
};
这个功能是:
constexpr Wrapper makeWrapper(int v)
{
return Wrapper(v);
}
以下代码无法为Clang(Apple LLVM版本7.3.0)编译,但对GCC(4.9)编译良好,两者都具有-Wall-Wpert-Werw-peandan-error
:
constexpr auto x = makeWrapper(123);
Clang抱怨“非constexpr构造函数‘Wrapper’不能在常量表达式中使用。”哪个编译器是对的?
虽然可以省略从makeWrapper()返回Wrapper
时的复制或移动,但它需要在C 14中存在。现有的拷贝构造函数是非Constexpr
,它的存在抑制了隐式移动构造函数的创建。因此,我认为clang是正确的:您需要将复制构造函数设置为Constexpr
。
请注意,使用C 17,代码可能会变得正确:在某些情况下,建议强制执行复制省略:P0135r0。然而,这一变化似乎还没有出现在工作文件中。不过,它可能会在本周着陆(感谢@NicolBolas指出它还没有着陆)。我在邮件中没有看到更新的论文。
叮当是正确的。它在g中工作,因为它自动省略了复制构造函数(RVO)。如果你传递-fno-elide-构造函数
。g也会抱怨。
C14标准不清楚Constrexr
对象中的Copy-Elision。
[class.copy/32]。。。(此处部分转载)
当满足复制/移动操作的省略标准时......即使省略了调用,选定的构造函数也必须是可访问的。
直到我们知道可访问性的定义
?我们可以假设g也是正确的?
dcl。constexpr/9
对象声明中使用的constexpr说明符将对象声明为const。此类对象应具有文字类型,并应初始化。如果由构造函数调用初始化,则该调用应为常量表达式([expr.const])。否则,或者如果引用声明中使用了constexpr说明符,则其初始值设定项中出现的每个完整表达式都应为常量表达式。
迪特马尔·库尔的回答告诉我们未来会发生什么。
演示:
struct Wrapper {
int value;
constexpr explicit Wrapper(int v) noexcept : value(v) {}
Wrapper(const Wrapper& that) noexcept : value(that.value) {}
};
constexpr Wrapper makeWrapper(int v)
{
return Wrapper(v);
}
int main()
{
constexpr auto x = makeWrapper(123);
}
编译
g++ -std=c++14 -Wall -pedantic -fno-elide-constructors main.cpp && ./a.out
看它住在这里
两个编译器都是对的。
函数和初始化函数的规则规定不能调用非函数。
复制省略规则表示,未指定是否调用非constexpr
copy构造函数。
唯一的结论是函数和初始化器是否满足constexpr
的要求尚不明确。如果他们这样做,那么编译器必须接受它。如果没有,则编译器必须诊断问题。