繁体   English   中英

类模板的静态成员错误

[英]static member of class template error

我对此代码段有疑问:

template <typename T>
struct S
{
  static int a;
};

template <typename T>
decltype(S<T>::a) S<T>::a;

clang-3.4说:

s.cpp:8:25: error: redefinition of 'a' with a different type: 'decltype(S<T>::a)' vs 'int'
decltype(S<T>::a) S<T>::a;
                        ^
s.cpp:4:14: note: previous definition is here
  static int a;
             ^
1 error generated.

但是gcc-4.8.2接受了。 哪个编译器是对的? 我将来应该避免这样的代码吗?

Clang要求定义在模板定义时匹配声明,而GCC和其他人推迟匹配直到实例化时间(从来没有发生过你的例子)。

Clang接受这个:

#include <type_traits>

template <typename T>
struct S
{
  static int a;
};

template <typename T>
typename std::enable_if< true, int >::type S<T>::a; // Resolves before instantiation

但拒绝这个小小的变化:

template <typename T>
typename std::enable_if< std::is_same< T, T >::value, int >::type S<T>::a;

我不记得在发生对象声明匹配时标准规定的位置,但我怀疑Clang是否有权拒绝代码。 如果我没记错的话,标准的意图是每个声明只匹配一个定义,并且可以在实例化时间之前确定该映射。

使用GCC显然适用的更宽松的规则,您可以有两个成员声明和两个定义,但每个定义可以根据模板参数完成任一个声明。

GCC和MSVC正在接受的代码是不正确的,不需要诊断......等待在[§3[基本],§7[dcl.dcl],§8[dcl.decl],§14中找到埋藏的实际标准。温度],或者其他地方。


我仍然无法找到哪些规则将对象定义与前面的声明匹配,但§14.4/ 2规定decltype(…)不能与int等效(我假设在声明意义上)。

如果表达式e涉及模板参数,则decltype(e)表示唯一的依赖类型。 两个这样的decltype-specifiers只有在它们的表达式是等价的时才引用相同的类型(14.5.6.1)。 [ 注意:但是,它可能是别名,例如,通过typedef-name。 - 结束说明 ]

我很确定定义匹配声明需要等效,而不仅仅是别名。 §14.5.6.1深入研究这个领域,除非它专门讨论功能签名。

我认为Clang 可能会拒绝这一点。 关于decltype(e) 14.2p2说

如果表达式e涉及模板参数,则decltype(e)表示唯一的依赖类型。

DR#2中 ,讨论描述说

我的观点(我认为与最近在反射器上发布的几个相匹配)是,类外定义必须与模板中的声明匹配。

...

通常,如果只使用模板中的信息匹配声明,则声明有效。

我认为如果其中一个使用typedef(如DR中所示),它仍然匹配,因为S<T>::type是当前实例化的成员,并且可以直接查找别名类型。 但是,如上所述, decltype(e)将始终表示唯一类型(在模板分析时间期间),除了指定等效表达式的另一个decltype(e)


为什么我说的威力 因为14.6p8

不能为可以生成有效特化的模板发出诊断。

人们可以读到这一点,因为类型等价检查只是延迟到实例化之后。 然而,这与我认为的DR中的讨论痕迹相矛盾,因为他们说“如果你只能使用模板中的信息来匹配声明,那么声明是有效的”(我认为这个声明的作者意味着在声明有效的情况下详尽无遗)。

对我来说,clang在这里打破了。

所有与decltype的组合都将失败。 没有decltype它工作。

template <typename T>
struct S
{   
      static int a;

      using type = decltype( a );
      typedef decltype( a ) type2;
};  

template <typename T>
1) decltype(S<T>::a) S<T>::a;
2) int S<T>::a;
3) typename S<T>::type S<T>::a;
4) typename S<T>::type2 S<T>::a;

1 gcc的作品,clang失败了

2 gcc + clang的作品

3 gcc作品,clang失败

4 gcc的作品,clang失败了

我做了一些尝试解决问题,但没有取得任何成功。

关于这类问题还有一些讨论: C ++静态成员初始化(模板内部有趣)

编辑:我发现这个主题在标准中只是“未解决”,直到现在并且clang没有实现它:看看: http//clang.llvm.org/cxx_dr_status.html (点205)

我希望我没有误解这个页面。 随意纠正我的解释。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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