繁体   English   中英

GCC和Clang对constexpr构造函数的不同行为

[英]GCC and Clang different behaviors on constexpr constructor

对于这个结构:

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 -Wextra -Werror -pedantic-errors

constexpr auto x = makeWrapper(123);

Clang抱怨说“非constexpr构造函数'Wrapper'不能用于常量表达式。” 哪个编译器是对的?

虽然可以省略从makeWrapper()返回Wrapper时的复制或移动,但它必须与C ++ 14一起存在。 现有的复制构造函数是非constexpr ,它的存在禁止创建隐式移动构造函数。 结果我认为clang是对的:你需要使复制构造函数成为constexpr

请注意,使用C ++ 17时,代码可能会变得正确:有一项建议要求在某些情况下强制执行copy-elision: P0135r0 然而,似乎这种变化尚未落入工作文件中。 它可能会在本周登陆(感谢@NicolBolas指出它不在那里)。 我没有在邮件中看到更新的论文。

铿锵是对的。 它在g ++中工作,因为它会自动删除复制构造函数(RVO)。 如果你传递-fno-elide-constructors g ++也会抱怨。

C ++ 14标准不清楚constexpr对象中的Copy-Elision。

[class.copy / 32] ... (部分转载于此处)

当满足复制/移动操作的省略标准时......即使呼叫被省略,所选构造函数也必须是可访问的。

直到我们知道accessible的定义? 我们可以假设g ++也是正确的吗?

dcl.constexpr / 9

对象声明中使用的constexpr说明符将对象声明为const。 这样的对象应具有文字类型并应初始化。 如果它是由构造函数调用初始化的,那么该调用应该是一个常量表达式([expr.const])。 否则,或者如果在引用声明中使用constexpr说明符,则其初始值设定项中出现的每个全表达式都应为常量表达式。

Dietmar Kuhl的回答告诉我们未来的发展方向。

演示:

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函数和初始化程序的规则表明不能调用非constexpr函数。

复制省略的规则表明,未指定非constexpr复制构造函数是否被调用。

唯一的结论是,未指定函数和初始化程序是否满足constexpr的要求。 如果他们这样做,那么编译器必须接受它。 如果他们不这样做,那么编译器必须诊断问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM