Tem*_*Rex 9 c++ clang static-members constexpr c++17
访问静态类成员函数或变量可以通过两种方式完成:通过对象(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() {}
Run Code Online (Sandbox Code Playgroud)
使用-std=c++1z和#define TEST 1为Clang 5.0 SVN编译的实例,错误消息:
Run Code Online (Sandbox Code Playgroud)Start prog.cc:12:24: error: constexpr variable 'v' must be initialized by a constant expression constexpr auto v = s.v(); // 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函数中静态成员访问的两种语法形式?
Sto*_*ica 10
Clang似乎是对的.使用成员访问语法[class.static/1]访问静态成员时:
可以使用qualified-id表达式X :: s来引用类X的静态成员; 没有必要使用类成员访问语法来引用静态成员.可以使用类成员访问语法来引用静态成员,在这种情况下,评估对象表达式.
因此s.v()将导致s评估.现在,根据[expr.const/2.11],s不是一个常量表达式:
2表达式e是核心常量表达式,除非根据抽象机器的规则评估e将评估以下表达式之一:
[...]
一个id-expression,引用引用类型的变量或数据成员,除非引用具有前面的初始化并且:
(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() {}
Run Code Online (Sandbox Code Playgroud)