表达式未求出恒定的两个级别的constexpr函数(编译器错误?)

时间:2019-07-04 16:08:10

标签: c++ templates c++17 constexpr compile-time-constant

我有以下代码:

#include <iostream>
template<int I>
class A
{
public:
    inline constexpr static int size() { return I; }
};

template<typename T>
inline constexpr auto size(const T& arg) noexcept -> decltype(arg.size())
{
    return arg.size();
}

template<typename T>
inline constexpr void twoLevel(const T& arg) noexcept
{
    static_assert(size(arg) > 0);
}

int main()
{
    A<5> a;
    static_assert(size(a)>0); //this works
    twoLevel(a); // this does not
    return 0;
}

在msvc上编译失败,错误为expression did not evaluate to a constant,但可以与gcc一起使用。 gcc是否接受某些不确定的行为?还是msvc方面的编译器错误? 这是一个演示:godbolt code

1 个答案:

答案 0 :(得分:1)

来自[expr.const]/4

  

表达式e核心常量表达式,除非根据抽象机的规则对e的求值将对以下表达式之一求值:      

      
  • [...]
  •   
  • 一个 id-expression ,它引用引用类型的变量或数据成员,除非引用具有前面的初始化且      
        
    • 它可用于常量表达式或
    •   
    • 其寿命始于e的评估;
    •   
  •   
  • [...]
  •   

在:

static_assert(size(arg) > 0);

我们有一个 id-expression 引用了引用类型的变量,并且该引用没有预先的初始化,因此我们没有常量表达式。

我认为:

static_assert(size(a) > 0);

之所以起作用,是因为“在先初始化”-我们通过将引用arg直接绑定到变量a来进入常量评估,而在另一种情况下,我们将引用绑定到另一个引用。

如果按价值衡量,两者都应该起作用。