static_assert未初始化的具有有效专用化的模板类中

static_assert in not initialized template class with valid specialization

本文关键字:专用 有效 assert 初始化 static      更新时间:2023-10-16

我的问题是,以下代码是否有效:

template<int i> class Class
{
static_assert(sizeof(i) == 0, "Class instantiated with i != 1");
};
template<> class Class<1> {};

此代码段使用g++进行编译。但clang++static_assert困住了:

error: static_assert failed "Class instantiated with non-int type"

使用类型而不是类似int的模板

template<typename T> class Class
{
static_assert(sizeof(T) == 0, "Class instantiated with non-int type");
};
template<> class Class<int> {};

被两个编译器接受。完全相同的模式适用于函数模板。

我找到了 open-std.org::非依赖static_assert声明,但这似乎不适用,因为我的static_assert依赖于模板参数。

您可以在 godbolt.org 上检查所描述的行为

编辑:正如Johan Lundberg在评论中指出的那样,我的问题错了。实际上,sizeof(i)不依赖于模板参数。R.Sahu 也是完全正确的:断言i != 1会更有意义。为此,两个编译器都接受代码。

但是,上面的示例仍然使用g++进行编译。由于open-std.org::非依赖static_assert声明适用于这种情况(我再次为这方面的错误问题道歉):g++编译代码而没有错误实际上是错误的吗?

clang++拒绝你的代码是正确的,但g++没有抓住错误并没有错;这是一个"不需要诊断"的情况。

该标准将模板中的表达式严格定义为"类型相关"和/或"值相关"。 给定template<int i>i是值依赖的,但不依赖于类型。

[14.6.2.2/4]:以下形式的表达式从不依赖于类型(因为表达式的类型不能依赖于):

  • sizeof一元表达式

[14.6.2.3/2]:如果一元表达式或表达式依赖于类型或类型ID依赖于,则以下形式的表达式是值相关的:

  • sizeof一元表达式

所以sizeof(i)不是依赖的。

最后,14.6/8 说:

如果紧跟在其定义之后的模板的假设实例化由于构造不依赖于模板参数而导致格式错误,则程序格式不正确;不需要诊断。

首先,如果要断言模板已使用错误的类型实例化,则必须在static_assert中明确:

#include <type_traits>
template<typename T> class Class
{
static_assert(std::is_same<T, int>::value, "Class instantiated with non-int type");

};

其次,以下行可能没有按照您的想法进行:

template<> class Class<int> {};

您在这里实际要做的是创建一个全新的专业化,这与默认的模板专业化Class<T>没有任何关系。

删除int的专用化并实例化默认专用化的非 int 类会在两个编译器中产生错误,因为它应该:

int main()
{
Class<int> ci;
Class<float> cf;
}

示例错误:

<source>: In instantiation of 'class Class<float>':
<source>:14:18:   required from here
<source>:5:5: error: static assertion failed: Class instantiated with non-int type
static_assert(std::is_same<T, int>::value, "Class instantiated with non-int type");
^~~~~~~~~~~~~