l值引用对象上的Constexpr成员函数:Clang和gcc不同意



当一个类具有 constexpr 成员函数并且该成员函数正在 constexpr 上下文中的 l 值对象上求值时,clang 和 gcc 不同意结果是否为 constexpr 值。 为什么?是否有既不需要默认可构造性也不需要复制可构造性的解决方法?

当对象按值传递时,两个编译器都会成功编译。

叮当版本树干,8,7:static_assert expression is not an integral constant expression

gcc 版本主干,8.1、7.4:编译没有错误

#include <array>
using A = std::array<int, 10>;
void foo(const A& a){
// clang: static_assert expression is not an integral constant expression
static_assert(a.size() > 0, "");
}

void foo2(A a){
// this compiles on both clang and gcc
static_assert(a.size() > 0, "");
}
// Some custom code with the same symptom:
class B{
public:
constexpr int size()const{
return 42;
}
};
void foo3(const B& b){
// clang: static_assert expression is not an integral constant expression
static_assert(b.size() > 0, "");
}

void foo4(B b){
// this compiles on both clang and gcc
static_assert(b.size() > 0, "");
}

https://godbolt.org/z/9vmyli

带有警告的解决方法:

void foo5(const B& b){
// This works in clang, if the default constructor is defined
static_assert(B().size() > 0, "");
}
void foo6(const B& b){
// This works in clang, if the copy constructor is defined
[](B b){static_assert(b.size() > 0, "");}(b);
}

由核心常量表达式的定义指定:

核心常量表达式是其计算将 不评估以下任何一项:

  1. 引用类型的变量或数据成员的id表达式,除非它使用常量表达式初始化 或其生命周期始于此表达式的评估

因此,您不允许在此处参考const A& a

例如,以下代码片段编译良好:

using A = std::array<int, 10>;
constexpr A arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
constexpr const A& arr_ref = arr;   // OK: arr_ref is initialized with a constant expr
static_assert(arr.size() > 0, "");
static_assert(arr_ref.size() > 0, "");

最新更新