Constexpr静态成员函数的用法

时间:2019-02-12 10:24:52

标签: c++ c++14 language-lawyer static-methods constexpr

请考虑以下示例代码:

#include <array>

struct MyClass
{
  size_t value = 0;

  constexpr static size_t size() noexcept
  {
    return 3;
  }
};

template <size_t N>
void DoIt()
{
  MyClass h;
  std::array<int, h.size()> arr;
}

int main()
{
  DoIt<1>();
}

当我尝试使用GCC 7.3.0进行编译时,出现关于h无法在非constexpr上下文中使用的错误:

cexpr.cpp: In function ‘void DoIt()’:
cexpr.cpp:17:26: error: the value of ‘h’ is not usable in a constant expression
   std::array<int, h.size()> arr;
                          ^
cexpr.cpp:16:11: note: ‘h’ was not declared ‘constexpr’
   MyClass h;
           ^
cexpr.cpp:17:27: error: the value of ‘h’ is not usable in a constant expression
   std::array<int, h.size()> arr;
                           ^
cexpr.cpp:16:11: note: ‘h’ was not declared ‘constexpr’
   MyClass h;
           ^

但是,当我尝试在Clang 6.0.0中编译完全相同的代码时,它的编译没有任何错误。另外,当我将代码修改为不在模板化的DoIt()函数内部时,GCC可以很好地进行编译:

#include <array>

struct MyClass
{
  size_t value = 0;

  constexpr static size_t size() noexcept
  {
    return 3;
  }
};

int main()
{
  MyClass h;
  // this compiles just fine in Clang and GCC
  std::array<int, h.size()> arr;
}

我已经知道如何修复第一个代码,因此它可以使用decltype在GCC上进行编译,但是我很好奇为什么第一部分代码不能与GCC一起编译?这只是GCC中的错误,还是我对使用constexpr静态成员函数不了解?

1 个答案:

答案 0 :(得分:5)

对我来说像个虫子。

表达式h.size()的类型和含义由[expr.ref]“类成员访问”定义:

  

[expr.post]/3

     

postfix-expression.id-expression 缩写为E1.E2E1被称为对象表达式。 [...]

  

[expr.post]/6.3.1

     

如果E2是一个(可能是重载的)成员函数,则使用函数重载解析来确定E1.E2是引用静态成员函数还是非静态成员函数。

     
      
  • (6.3.1)如果引用静态成员函数并且E2的类型是“返回T的参数类型列表的函数”,则E1.E2是一个左值表达式指定静态成员函数E1.E2的类型与E2的类型相同,即“参数类型列表返回T的功能”。
  •   

这意味着h.size具有与::MyClass::size相同的类型,并且被这样评估,无论h是否为constexpr都是如此

h.size()是对constexpr函数的调用,并且是根据[expr.const]/4核心常量表达式