Constexpr member function on l-value ref object: Clang and gcc disagree

耗尽温柔 提交于 2021-02-07 06:05:53

问题


When a class has a constexpr member function and that member function is being evaluated on an l-value object in a constexpr context, clang and gcc disagree whether the result is a constexpr value. Why? Is there a workaround that needs neither default-constructability nor copy-constructability?

When the object is passed by value, both compilers succeed compiling.

Clang versions trunk, 8, 7: static_assert expression is not an integral constant expression

and

Gcc versions trunk, 8.1, 7.4: compiles with no error

#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

Workarounds with caveats:

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:


As specified by the definition of core constant exprssions:

A core constant expression is any expression whose evaluation would not evaluate any one of the following:

...

  1. an id-expression referring to a variable or a data member of reference type, unless it was initialized with a constant expression or its lifetime began within the evaluation of this expression

...

So you are not allowed to have reference const A& a here.

As an example, the following snippet compiles fine:

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, "");


来源:https://stackoverflow.com/questions/57779870/constexpr-member-function-on-l-value-ref-object-clang-and-gcc-disagree

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!