static_assert依赖于非类型模板参数(gcc和clang上的不同行为) [英] static_assert dependent on non-type template parameter (different behavior on gcc and clang)

查看:261
本文介绍了static_assert依赖于非类型模板参数(gcc和clang上的不同行为)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  template< int answer> struct Hitchhiker {
static_assert(sizeof(answer)!= sizeof(answer),Invalid answer);
};

模板<> struct Hitchhiker< 42> {};

尝试使用 static_assert 我发现 clang 中的上述代码即使在模板未实例化时也会生成assert错误,而 gcc 生成只有在使用 42 之外的参数实例化 Hitchhiker 时,才会发生断言错误。



我发现这个断言:

 模板< int answer> struct Hitchhiker {
static_assert(sizeof(int [answer])!= sizeof(int [answer]),Invalid answer);
};

模板<> struct Hitchhiker< 42> {};

在两个编译器上的行为相同:assert只有在实例化通用模板时才会执行。 p>

标准是什么,哪个编译器是正确的?

  g ++ 4.9 .2 
clang ++ 3.50


解决方案

@TartainLlama


如果一个模板的假设实例化紧接着它的定义将是不成形的,因为一个结构不依赖于模板参数,程序是不成形的;无需诊断。


N4296 [temp.res] / 8 b

这在主模板定义之后立即应用(其中包含 static_assert 的模板)。因此,后来的专业化( 42 )不能被考虑,因为它还不存在。



is if static_assert(sizeof(answer)!= sizeof(answer), depends on answer



在模板中,一些构造具有可能不同于语义的语义,这样的构造取决于模板参数。


N4296 [temp .dep] / 1



构建 sizeof(answer)!= sizeof(answer)因此这样的构造不依赖于模板参数,这意味着整个 static_assert 不依赖于模板参数



因此你的程序是不成形的,不需要诊断。发出一个任意的诊断(如 static_assert failing)是有效的编译器行为。缺少问题是有效的编译器行为。从一个不成熟的,没有诊断所需的程序编译的程序的行为没有被标准定义:它是未定义的行为。允许鼻甲。



花式尝试(如 sizeof(int [answer])!= sizeof(int [answer])可以请当前的 god 编译器,但不会使你的程序更好的形成。



不太可能抓住你,但是形式不变仍然保持编译器捕捉你的能力。作为一般规则,C ++想要让自己(和它的编译器)自由地找到



这可能是你想要的东西像 = delete ,附有邮件。


template <int answer> struct Hitchhiker {
  static_assert(sizeof(answer) != sizeof(answer), "Invalid answer");
};

template <> struct Hitchhiker<42> {};

While trying to disable general template instantiation with static_assert I discovered that the above code in clang generates the assert error even when the template is not instantiated, while gcc generates the assert error only when instantiating Hitchhiker with a parameter other than 42.

Fiddling around I found that this assert:

template <int answer> struct Hitchhiker {
  static_assert(sizeof(int[answer]) != sizeof(int[answer]), "Invalid answer");
};

template <> struct Hitchhiker<42> {};

behaves the same on both compilers: the assert kicks in only when the general template is instantiated.

What does the standard says, which compiler is right?

g++ 4.9.2
clang++ 3.50

解决方案

Quotes found by @TartainLlama

If a hypothetical instantiation of a template immediately following its definition would be ill-formed due to a construct that does not depend on a template parameter, the program is ill-formed; no diagnostic is required.

N4296 [temp.res]/8

This applies immediately after the primary template is defined (the one with the static_assert in it). So the later specialization (for 42) cannot be considered, as it does not exist yet.

The next question is if static_assert( sizeof(answer) != sizeof(answer), depends on answer. Semantically it does not, syntactically it does, and standard-wise:

Inside a template, some constructs have semantics which may differ from one instantiation to another. Such a construct depends on the template parameters.

N4296 [temp.dep]/1

The construct sizeof(answer) != sizeof(answer) does not differ from one instantiation to another. So such a construct does not depend on the template parameters. Which means the entire static_assert does not depend on the template parameter.

Thus your program is ill formed, no diagnostic required. Issuing an arbitrary diagnostic (such as the static_assert failing) is valid compiler behavior. Missing the problem is valid compiler behavior. The behavior of a program compiled from an ill formed, no diagnostic required program is not defined by the standard: it is undefined behavior. Nasal demons are permitted.

Fancy attempts (like sizeof(int[answer])!=sizeof(int[answer]) may please the current god compiler, but does not make your program more well formed.

You could make a case where the compiler is unlikely to be able to catch you at it, but the ill-formed-ness remains regardless of the ability for the compiler to catch you with it. As a general rule, C++ wants to leave itself (and its compilers) freedom to find invalid template code "earlier than instantiation"; this means that template code must produce possibly legal code.

It is possible you want something like =delete with a message attached.

这篇关于static_assert依赖于非类型模板参数(gcc和clang上的不同行为)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆