考虑以下示例代码:
#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 静态成员函数有什么不明白的地方?
最佳答案
在我看来是个错误。
表达式h.size()
的类型和含义由[expr.ref]
“类成员访问”定义:
[expr.post]/3
Abbreviating postfix-expression.id-expression as
E1.E2
,E1
is called the object expression. [...]
和
[expr.post]/6.3.1
If
E2
is a (possibly overloaded) member function, function overload resolution is used to determine whetherE1.E2
refers to a static or a non-static member function.
- (6.3.1) If it refers to a static member function and the type of
E2
is “function of parameter-type-list returningT
”, thenE1.E2
is an lvalue; the expression designates the static member function. The type ofE1.E2
is the same type as that ofE2
, namely “function of parameter-type-list returningT
”.
这意味着 h.size
具有与 ::MyClass::size
相同的类型,并且被评估为这样,不管 h
是 constexpr
还是不是。
h.size()
然后是对 constexpr
函数的调用,并且是根据 [expr.const]/4
的 核心常量表达式 .
关于c++ - constexpr 静态成员函数用法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54647876/