【发布时间】:2014-02-15 21:40:01
【问题描述】:
这是一个简短的独立测试用例来解释我的问题。 GCC 接受此代码,但 clang 和 Intel 拒绝它:
template <typename T>
struct false_t {
static const bool value = false;
};
template <typename T>
int f() {
static_assert(false_t<T>::value, "");
return 0;
}
template <typename T>
struct S {
int m = f<T>();
};
int s = sizeof(S<int>);
或者,根据 pmr 的评论,这是一个更简单的示例,它也被 gcc 接受并被 clang 拒绝:
struct S;
template <typename T> struct X { int x = T(); };
int s = sizeof(X<S>);
sizeof(S<int>)(或sizeof(X<S>))应该实例化它需要的类的位,但编译器不同意这些位。由于非静态数据成员初始化器只能由构造函数使用,因此 GCC 将实例化作为实例化类的构造函数的一部分来执行。 clang 和 Intel 更早地这样做了。
我无法理解标准在 [temp.inst]p1 中所说的内容:
类模板特化的隐式实例化导致隐式 类成员函数、成员类、范围成员枚举、静态数据成员和成员模板的声明的实例化,但不是定义或默认参数的实例化;它会导致无范围成员枚举和成员匿名联合的定义的隐式实例化。
因为我根本看不到非静态数据成员(有或没有初始化器)的声明在哪里被实例化。
关于我在哪里遇到这个问题的更多细节:我正在尝试创建一个模板帮助程序类(永远不会在运行时创建),其中包含一个使用 std::declval<T>() 初始化的成员(我应该补充一下,我现在意识到会无论如何都没有多大用处),并且 libstdc++ 的std::declval 实现包含一个静态断言,就像我的示例中的断言一样。通过避免std::declval,我可以毫不费力地解决这个问题,但我想知道标准要求什么。
【问题讨论】:
-
也许你应该使用
sizeof(S<int>)而不是sizeof(S<int>::m)。似乎只是掩盖了意图,结果是一样的。 -
@pmr 我在选择其中一个时遇到了麻烦,并且不知何故在代码中使用了后者,但在我对代码的描述中使用了前者。代码现已编辑为使用
sizeof(S<int>),谢谢。 -
我遇到了这个问题的简单重现:
struct S; template<typename T> struct X { int x = T().i; }; unsigned n = sizeof(X<S>); -
@pmr 不错,这要简单得多!事实上,你甚至不需要那里的
.i。
标签: c++ c++11 language-lawyer