左值ref对象上的Constexpr成员函数:Clang和gcc不同意

Jan*_*n15 8 c++ constexpr c++11

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

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

lang版本的树干8、7: static_assert expression is not an integral constant expression

Gcc版本trunk,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, "");
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

Kae*_*Rin 3

正如核心常量表达式的定义所指定的:

核心常量表达式是其计算不会计算以下任何一项的任何表达式:

...

  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, "");
Run Code Online (Sandbox Code Playgroud)