49

I use g++ 4.6.3, (currently default package for ubuntu 12.04) with the flag c++0x, and I stumble across this:

template <typename T>
inline T getValue(AnObject&)
{
    static_assert(false , "this function has to be implemented for desired type");
}

with the compilation error:

static_assertion failed "this function has to be implemented for the desired type"

even though I don't call this function anywhere yet.

Is it a g++ bug ? Shouldn't this function be instanciated only if it is called somewhere in the code.

ildjarn
  • 62,044
  • 9
  • 127
  • 211
Stephane Rolland
  • 38,876
  • 35
  • 121
  • 169

4 Answers4

73

The standard says in [temp.res]/8

No diagnostic shall be issued for a template definition for which a valid specialization can be generated. 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. ... [ Note: If a template is instantiated, errors will be diagnosed according to the other rules in this Standard. Exactly when these errors are diagnosed is a quality of implementation issue. — end note ]

There is no possible way to instantiate your function template that will compile, so the template definition is ill-formed and so the compiler is allowed (but not required) to reject it even if it isn't instantiated.

You could make it work like this:

template<typename T>
struct foobar : std::false_type
{ };

template <typename T>
inline T getValue(AnObject&)
{
    static_assert( foobar<T>::value , "this function has to be implemented for desired type");
}

Now the compiler cannot reject the function template immediately, because until it is instantiated it doesn't know whether there will be a specialization of foobar that has value == true. When instantiated the relevant specialization of foobar<T> will be instantiated and the static assertion will still fail, as desired.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
34

That's because the condition does not depend in any way on the template parameters. Therefore, the compiler can evaluate it even before instantiating that template, and produces the associated compilation error message if it the evaluation yields false.

In other words, this is not a bug. Although many things can only be checked once a template is instantiated, there are other validity checks that a compiler can perform even before. This is why C++ has a two-phase name lookup, for instance. The compiler is just trying to help you finding errors that are 100% likely to occur.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Can you confirm that this function is instanciated even though I call it nowhere in the code ? Is that what you said ? – Stephane Rolland Jan 31 '13 at 23:59
  • @StephaneRolland: The function is not instantiated, only the `static_assert()` instruction is executed. – Andy Prowl Feb 01 '13 at 00:01
  • in which case it is also totally different from the static_assert that Andrei Alexandrescu had proposed in his book "Modern C++ Design". – Stephane Rolland Feb 01 '13 at 00:07
  • 1
    @StephaneRolland: I do not remember how Alexandrescu defined it, but that's very likely. After all, this is a new language feature, not just a library. Similarly, if you write a function call to `foo()` in your template function `getValue()`, and no function `foo()` exist, your code won't compile, because the compiler knows that there is no way you could instantiate that template in a way that it would compile. – Andy Prowl Feb 01 '13 at 00:10
  • So I am in the quest for a another way to static_assert like, but only at template instanciation time :-) – Stephane Rolland Feb 01 '13 at 00:14
  • 6
    @StephaneRolland: then use `static_assert()`, but make the condition *dependent* on some template argument. Make it such that it will always yield `false` for the arguments you are going to instantiate it with (e.g. `static_assert(typename is_same::value), "Error!")`, but do mention the template argument in the condition. This will tell the compiler: "Hey, this is a dependent name, so wait until instantiation before judging..." – Andy Prowl Feb 01 '13 at 00:16
  • @StephaneRolland: That trick was actually wrong :-) Or... it did the work, in that it generated a compile-time error, but not the one you probably expected: it was an error evaluating the condition itself, so the condition never got evaluated to `false`, which in turn means the associated message was not displayed. I updated my comment. – Andy Prowl Feb 01 '13 at 00:20
  • 2
    @StephaneRolland: Note that `static_assert(sizeof(T) == 0, "Error!")` is usually brought up as another solution, but I *think* the concensus is that this can fail "early" as well, because the compiler can know the size is never less than 1 without even looking at `T`. Just to keep that out there. – GManNickG Feb 01 '13 at 00:38
  • This is the problem - if you write something like static_assert( N!=N, "oops") ... where N is an 'int' template parm (or a static consexpr derived from template parms), then it works now, but maybe some compiler will notice that it can't ever be true. Seems like there should be a better solution (and, maybe a guarantee that any expression with template dependencies, regardless of how trivial, will be deferred until instantiation? so even `false && N` should work ). – greggo Dec 04 '19 at 20:49
  • The same problem arises with `if constexpr (...) { ... } else if constexpr ( ... ) { ... } else { static_assert(false, "not supported); }`- the `false` needs to be changed to something with a template dependency, or it fails when the template is analyzed. – greggo Dec 04 '19 at 20:53
5

This is really a comment, but requiring a code example.

The holy standard's wording for static_assert does not limit its effect to instantiated code.

However, the code

template <typename T>
inline T getValue(int&)
{
    typedef char blah[-1];  // Common C++03 static assert, no special semantics.
}

int main()
{}

also fails to compile with MinGW g++ 4.7.2, which accentuates the question.

I think the answer is that g++ is right, and that Visual C++ 11.0, which does not produce a compilation error for this, is wrong, but I'd be hard pressed to provide the relevant analysis in terms of the Holy Standard's verses.

A practical consequence of the compiler difference is that presently you can not rely on the behavior.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
0

just -fdelayed-template-parsing

吴带爷
  • 27
  • 3