[英]Static member access in constant expressions
可以通过两种方式访问静态类成员函数或变量:通过对象( obj.member_fun()
或obj.member_var
)或通过类( Class::member_fun()
或Class::member_var
)。 但是,在constexpr
函数中,Clang 给出了对象访问错误,需要使用类访问:
struct S
{
constexpr static auto s_v = 42;
constexpr static auto v() { return s_v; }
};
#define TEST 1
constexpr auto foo(S const& s [[maybe_unused]])
{
#if TEST
constexpr auto v = s.v(); // ERROR for clang, OK for gcc
#else
constexpr auto v = S::v(); // OK for clang and gcc
#endif
return v;
}
constexpr auto bar(S const& s [[maybe_unused]])
{
#if TEST
constexpr auto v = s.s_v; // ERROR for clang, OK for gcc
#else
constexpr auto v = S::s_v; // OK for clang and gcc
#endif
return v;
}
int main() {}
使用-std=c++1z
和#define TEST 1
为 Clang 5.0 SVN 编译的实时示例,带有错误消息:
Start prog.cc:12:24: error: constexpr variable 'v' must be initialized by a constant expression constexpr auto v = sv(); // ERROR for clang, OK for gcc ^~~~~ prog.cc:22:24: error: constexpr variable 'v' must be initialized by a constant expression constexpr auto v = s.s_v; // ERROR for clang, OK for gcc ^~~~~ 2 errors generated. 1 Finish
问题:这是一个 Clang 错误,还是 gcc 过于宽松地接受constexpr
函数中静态成员访问的两种语法形式?
Clang似乎是对的。 使用成员访问语法[class.static/1]访问静态成员时:
类 X 的静态成员 s 可以使用限定 id 表达式 X::s 来引用; 没有必要使用类成员访问语法来引用静态成员。 可以使用类成员访问语法引用静态成员,在这种情况下,将评估对象表达式。
所以sv()
将导致s
被评估。 现在,根据[expr.const/2.11] , s
不是常量表达式:
2 表达式 e 是核心常量表达式,除非按照抽象机的规则对 e 的求值会求值以下表达式之一:
[...]
引用引用类型的变量或数据成员的 id 表达式,除非该引用具有先前的初始化,并且:
(2.11.1) - 用常量表达式初始化或
(2.11.2) - 它的生命周期从 e 的计算开始;
s
之前没有使用常量表达式进行初始化,不在foo
的范围内。
如果你想访问基于函数参数的静态成员,而不对类型进行硬编码,前进的方向是std::remove_reference_t<decltype(s)>
。 Clang 和 GCC 都接受了这一点:
#include <type_traits>
struct S
{
constexpr static auto s_v = 42;
constexpr static auto v() { return s_v; }
};
constexpr auto foo(S const& s)
{
constexpr auto v = std::remove_reference_t<decltype(s)>::v();
return v;
}
constexpr auto bar(S const& s)
{
constexpr auto v = std::remove_reference_t<decltype(s)>::s_v;
return v;
}
int main() {}
constexpr auto v = s.v(); // ERROR for clang, OK for gcc
我想这取决于你是在 C++11 还是 C++14 模式下编译。 如果您查看cppreference ,您会发现(强调由我添加):
核心常量表达式是不具有以下任何一项的任何表达式
(...)
6)this
指针,除非用于非静态成员函数内部的类成员访问(C++14 前)
6)this
指针,在 constexpr 函数或作为表达式的一部分被计算的 constexpr 构造函数中除外 (C++14 起)
因此,在 C++11 中,无论sv()
内部发生什么,都不会被视为常量表达式,因为它使用this
指针,但它不是访问类成员的非静态成员函数(它是static
)。
然而,根据 C++14,它会是,因为它正在评估一个constexpr
函数作为表达式的一部分,所以“没有任何”规则集上的“except if”子句会被捕获。
现在不要问我这是否有意义,或者是否有人应该理解……:-)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.