首页 > 解决方案 > 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;
}

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

标签: c++c++14language-lawyerstatic-methodsconstexpr

解决方案


对我来说似乎是一个错误。

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

[expr.post]/3

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

[expr.post]/6.3.1

ifE2是一个(可能重载的)成员函数,函数重载决议用于确定是E1.E2指静态成员函数还是非静态成员函数。

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

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

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


推荐阅读