Constexpr静态成员函数用法

hel*_*922 20 c++ static-methods language-lawyer constexpr c++14

请考虑以下示例代码:

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

当我尝试使用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;
           ^
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试在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;
}
Run Code Online (Sandbox Code Playgroud)

我已经知道如何修复第一个代码,因此它在GCC上编译使用decltype,但我很想知道为什么第一段代码不能用GCC编译?这只是GCC中的一个错误,还是我对使用constexpr静态成员函数有些不了解?

YSC*_*YSC 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和被评价为这样,不管这一事实hconstexpr或不是

h.size()然后到一个呼叫constexpr功能,并且是核心常量表达式根据[expr.const]/4

  • 有趣的是,MyClass h; std :: array &lt;int,h.size()&gt; arr;`被gcc主干拒绝,但是`std :: array &lt;int,MyClass {}。size()&gt; arr;`被接受:https:// godbolt .org / z / GtStLT (2认同)