繁体   English   中英

常量表达式中的静态成员访问

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM