【发布时间】:2017-05-06 22:04:38
【问题描述】:
例如:
class example{
public:
template <class T> static constexpr T var = T(1.5);
};
int main(){
int a = example::var<int>;
example obj;
int b = obj.var<int>;
return 0;
}
GCC 对两者都产生错误:
'example::var<T>' is not a function template 和 'var' is not a member template function
Clang 正确编译了第一个,但产生了第二个错误:cannot refer to member 'var' in 'example' with '.'
根据 C++14 标准 (ISO/IEC 14882:2014):
第 14 节,第 1 段。
类范围的变量模板是静态数据成员模板。
第 9.4 节,第 2 段。
类 X 的静态成员 s 可以使用限定 ID 表达式 X::s 来引用;不必使用类成员访问语法 (5.2.5) 来引用静态成员。可以使用类成员访问语法来引用静态成员,在这种情况下,对象表达式会被求值。
因此,恕我直言,类范围的变量模板(即静态数据成员模板)可以以两种方式引用。会不会是编译器的bug?
我发现试图证明这种行为的唯一方法是第 9.4.2 节第 1 段中的这句话:
静态数据成员不是类的子对象的一部分。
但是,上述两段仍然有效。此外,我尝试了引用其他静态成员(如变量、函数和函数模板)的相同示例,并且它们都在 GCC 和 Clang 中编译成功。
class example{
public:
static int constexpr variable = 1;
void static function(){ return; }
template <class T> void static function_template(){ return; }
};
int main(){
example obj;
int a = obj.variable;
int b = example::variable;
obj.function();
example::function();
obj.function_template<int>();
example::function_template<int>();
return 0;
}
提前致谢。
注 1:编译器版本为 clang 3.7.0 和 gcc 5.2.1。
注2:关键字static为必填项:Variable template at class scope
注3:由于我要初始化变量模板,所以关键字constexpr也是必需的,因为在我的实际代码中我会用float、double和long double来实例化它(参见C++14标准(ISO/IEC 14882:2014),第 9.4.2 节,第 3 段)。
注意 4:在本示例情况下,类外部的这些静态数据成员(即template <class T> constexpr T example::var;)的实际“定义”是不需要的。不过我也试过了,但没什么区别。
【问题讨论】:
-
您使用的是哪个版本的 gcc? g++ 6.2 的行为就像铿锵声。但与 clang 不同的是,
obj.var<int>的错误消息是 “var不是成员模板函数”。从 g++ 5 开始,第一部分似乎已经修复。 -
我正在使用 gcc 5.2.1 和 clang 3.7.0 :)
-
Clang trunk 接受此代码。
-
只是说,第 9.4.2 节,第 1 段与此无关,它是关于对象布局而不是访问语法
-
感谢@OlegBogdanov 的评论,我不完全确定该特定句子适用于什么:)
标签: c++ templates c++14 static-members variable-templates