我对此代码段有疑问:
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
接受了。哪个编译器是对的?我将来应该避免使用这些代码吗?
答案 0 :(得分:3)
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[temp],或者其他地方。
我仍然无法找到哪些规则将对象定义与前面的声明匹配,但是§14.4/ 2规定decltype(…)
不能与int
等效(我假设在声明意义上)。
如果表达式 e 涉及模板参数,
decltype(e)
表示唯一的依赖类型。两个这样的 decltype-specifiers 是指 只有当它们的表达式相同时才能使用相同的类型(14.5.6.1)。 [注意:但是,它可能是别名,例如,通过 typedef-name。 - 结束 注意]
我很确定定义匹配声明需要等效,而不仅仅是别名。 §14.5.6.1深入研究这个领域,除非它专门讨论功能签名。
答案 1 :(得分:3)
我认为Clang 可能正确拒绝这一点。 14.2p2说decltype(e)
如果表达式e涉及模板参数,则decltype(e)表示唯一的依赖类型。
在DR #2中,讨论痕迹显示
我的观点(我认为与最近在反射器上发布的几个相匹配)是,类外定义必须与模板中的声明相匹配。
...
通常,如果只使用模板中的信息匹配声明,则声明有效。
我认为如果其中一个使用typedef(如DR中所示),它仍然匹配,因为S<T>::type
是当前实例化的成员,并且可以直接查找别名类型。但是,如上所述,decltype(e)
将始终表示唯一类型(在模板分析时间内),除了指定等效表达式的另一个decltype(e)
之外。
为什么我说可能?因为14.6p8
不能为可以生成有效特化的模板发出诊断。
可以读到这一点,因为类型等价检查只是延迟到实例化之后。然而,这与我认为的DR中的讨论痕迹相矛盾,因为他们说如果你能够仅使用来自模板的信息来匹配声明,那么声明是有效的&#34; (并且我假设本声明的作者意图详尽说明声明有效时的情况。)
答案 2 :(得分:2)
对我来说,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++ Static member initalization (template fun inside)
编辑: 我发现这个主题只是简单地解决了#34;在标准到现在为止,clang没有实现它: 看一眼: http://clang.llvm.org/cxx_dr_status.html(第205点)
我希望我没有误解这个页面。随意纠正我的解释。