static_assert dependent on non-type template parameter (different behavior on gcc and clang)

江枫思渺然 提交于 2019-11-26 13:48:26

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.

Both compilers are correct. From [temp.res]/8:

If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required.

There does not exist a valid specialization that can be generated from the primary template Hitchhiker, so it is ill-formed, no diagnostic required. clang chooses to issue a diagnostic anyway.

If you only want to allow 42, then simply don't define the general template:

template <int > struct Hitchhiker;
template <> struct Hitchhiker<42> {};
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!