【问题标题】:Constexpr member function on l-value ref object: Clang and gcc disagreel 值引用对象上的 Constexpr 成员函数:Clang 和 gcc 不同意
【发布时间】:2019-09-03 23:45:53
【问题描述】:

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

对象传值时,两个编译器都编译成功。

Clang 版本主干、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, "");
}

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);
}

【问题讨论】:

  • 可以将size定义为静态成员函数,使用B::size()。

标签: c++ c++11 constexpr


【解决方案1】:

如core constant exprssions的定义所指定:

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

...

  1. 一个 id-expression 引用一个变量或引用类型的数据成员,除非它是用常量表达式初始化的 或者它的生命周期开始于这个表达式的评估

...

所以你不能在这里引用const A&amp; a。

例如,下面的 sn-p 编译良好:

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

【讨论】:

  • 谢谢!就A 不需要默认构造而言,您能想出一种比问题中更好的解决方法吗? std::declval 有同样的问题,因为它返回一个引用。而像constexpr A dummy(); 这样的声明是不够的,因为constexpr 需要dummy 的定义。
猜你喜欢
  • 2020-06-12
  • 2016-07-29
  • 1970-01-01
  • 2020-05-26
  • 1970-01-01
  • 2019-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多