53

In C++11, should the operation of static_assert within a template depend on whether that template has been instantiated or not? For example, with the following code

template <int I>
void sa() { static_assert(0,"Hello."); }

int main(int argc, char *argv[]) { return 0; }

GCC 4.5.0 will fail the assertion, and produce the "Hello." message. The Digital Mars Compiler version 8.42n on the other hand, gives no message.

user2023370
  • 10,488
  • 6
  • 50
  • 83
  • The compiler is expected to build an AST for the template when it sees it. I've tested this with gcc 4.5 myself, and if anything in the static_assert expression depends on the template argument, you no longer get an error message. I'm not sure what the correct behavior is either. It might be that both are acceptable. – Omnifarious Mar 09 '11 at 12:58
  • 3
    Weird. What happens when you make the assertion depend on `I`? For example, try asserting `sizeof I == 0` which should always be `false`. – Konrad Rudolph Mar 09 '11 at 12:59

5 Answers5

54

GCC is correct and the other compiler is correct too. Refer to 14.6p8 in the spec

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

Therefor, a compiler is free to reject the following

template<typename T>
void f() {
  static_assert(0, "may trigger immediately!");
  static_assert(sizeof(T) == 0, "may trigger immediately!");
}

If you want to go safe, you have to arrange it so the compiler cannot know until instantiation whether the boolean expression will be true or false. For example, get the value by getvalue<T>::value, with getvalue being a class template (one could specialize it, so the compiler cannot possibly know the boolean value already).

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
9

I believe that the compiler is well within it's rights to expand any static assertions that are not dependent on template parameters without needing an instantiation- but I don't believe this is required. Remember also that different draft Standards may have different rules about when this may occur.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • Except for one small problem. Template specializations can make code dependent on template arguments in non-obvious ways because it may arrange for cases in which that code is never expanded. Since a template specialization can occur well after a template definition, this means the compiler cannot give an error for the template definition even if it can determine that the static_assert would always fail. – Omnifarious Mar 09 '11 at 13:15
  • @Omnifarious: Except when the compiler is finished with the translation unit, it knows whether or not to trigger the assert, because it's seen all the specializations. – Puppy Mar 09 '11 at 13:16
  • Well, that might be the case, and would be a good argument if that's what gcc 4.5 is doing, but it isn't. I added a specialization that did not have the `static_assert`, and the `static_assert` still triggered. – Omnifarious Mar 09 '11 at 13:19
  • 1
    @Omnifarious: That's because the `static_assert` is not dependent on the template parameter in any way, making it impossible for you to remove the fact that it failed. – Puppy Mar 09 '11 at 13:34
5

The C++0x draft (N3242) says in 14.6p8:

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

The same words appear in the C++03 standard.

In the case of the example from the question, no valid instantiation can be made for this template, so the quoted wording applies.

Since no diagnostic is required, the compiler may compile the program if the template is not instantiated. Of course, if it is instantiated then the program is ill-formed, with a diagnostic required.

Anthony Williams
  • 66,628
  • 14
  • 133
  • 155
4

I used a helper function to make the false dependent on the template parameter:

template<typename T> 
bool dependentFalse<T>()
{
    return false;
}

template<typename T>
Foo foo()
{
    static_assert(dependentFalse<T>(), "this template shouldn't be instantiated");
}
starblue
  • 55,348
  • 14
  • 97
  • 151
  • I don't know what this is, but it surely does't compile. – cubuspl42 Dec 04 '12 at 15:41
  • 1
    @cubuspl42 it's missing constexpr for the dependentFalse template. (remember also to define a Foo type and such if you're just going to copy/paste this and compile) – Alec Teal Sep 02 '13 at 15:03
3

This is 14.6.2 section in C++ standard.

Your static_assert is related to support binding nondependent names when initially parsing a template. The Digital Mars Compiler does not currently support binding nondependent names. GCC 4.5.0 does support binding nondependent names.

If your expression does not depend on the template parameters then such expression is known when initially parsing a template. Compiler must show the error message. GCC 4.5.0 does it.

Replace your 0 in static_assert with I*I < 0, for expample and you get dependent name. Error message will appear for the case of uninstantiated template only.

Alexey Malistov
  • 26,407
  • 13
  • 68
  • 88
  • 1
    Anthony and Johannes quote "no diagnostic required" from the C++0x standard at 14.6.8 in [N3242](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf) – user2023370 Mar 09 '11 at 14:51