Templates compilation: gcc vs VS2010 - c++

From the book - C++ Templates: The Complete Guide by David, Nicolai
Thus, templates are compiled twice:
Without instantiation, the template code itself is checked for correct syntax. Syntax errors are discovered, such as missing
semicolons.
At the time of instantiation, the template code is checked to ensure that all calls are valid. Invalid calls are discovered, such as
unsupported function calls.
Keeping the first point, I wrote -
template<typename T>
void foo( T x)
{
some illegal text
}
int main()
{
return 0;
}
It build fine on Visual Studio 2010 with out any warnings with optimizations turned off. How ever, it failed on gcc-4.3.4. Which one is complying to the C++ standard ? Is it mandatory for template code to get compiled even with out template instantiation ?

The program in question is ill-formed, but the C++ standard does not require a diagnostic in this case, so both Visual Studio and GCC are behaving in a compliant fashion. From §14.6/7 of the C++03 standard (emphasis mine):
Knowing which names are type names allows the syntax of every template definition to be checked. 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. If a type used in a non-dependent name is incomplete
at the point at which a template is defined but is complete at the point at which an instantiation is done, and
if the completeness of that type affects whether or not the program is well-formed or affects the semantics
of the program, the program is ill-formed; no diagnostic is 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. ] [Example:
int j;
template<class T> class X {
// ...
void f(T t, int i, char* p)
{
t = i; // diagnosed if X::f is instantiated
// and the assignment to t is an error
p = i; // may be diagnosed even if X::f is
// not instantiated
p = j; // may be diagnosed even if X::f is
// not instantiated
}
void g(T t) {
+; //may be diagnosed even if X::g is
// not instantiated
}
};
—end example]

The book you're looking at seems to reflect (mostly) that author's observations about how compilers really work, not the requirement(s) of the standard. The standard doesn't really say much to give extra leniency to a compiler about ill-formed code inside a template, just because it's not instantiated.
At the same time, the book is correct that there are some things a compiler really can't do much about checking until it's instantiated. For example, you might use a dependent name as the name of a function (or invoke it like a function, anyway -- if it's functor instead that would be fine too). If you instantiate that template over a class where it is a function, fine and well. If you instantiate it over a class where it's really an int, attempting to call it will undoubtedly fail. Until you've instantiated it, the compiler can't tell which is which though.
This is a large part of what concepts were really intended to add to C++. You could directly specify (for example) that template X will invoke T::y like a function. Then the compiler could compare the content of the template with the declarations in the concept, and determine whether the body of the template fit with the declaration in the concept or not. In the other direction, the compiler only needed to compare a class (or whatever) to the concept to determine whether instantiating that template would work. If it wasn't going to work, it could report the error directly as a violation of the relevant concept (as it is now, it tries to instantiate the template, and you frequently get some strange error message that indicates the real problem poorly, if at all).

Related

Dependent non-type parameter packs: what does the standard say?

I think the following code is well-formed:
template< typename T >
using IsSigned = std::enable_if_t< std::is_signed_v< T > >;
template< typename T, IsSigned< T >... >
T myAbs( T val );
Others say that it is ill-formed, because §17.7 (8.3) of the C++17 standard:
Knowing which names are type names allows the syntax of every template to be checked. The program is ill-formed, no diagnostic required, if: (...) every valid specialization of a variadic template requires an empty template parameter pack, or (...)
In my opinion IsSigned< T >... is a dependent template parameter, therefore it can not be checked against §17.7 (8.3) in template definition time. IsSigned< T > could be for example void for one subset of Ts, int for another subset or substitution failure. For the void subset it is true, that the empty template parameter pack would be the only valid specialization, but the int subset could have many valid specializations. It depends on the actual T argument.
It means that the compiler must check it after the template instantiation, because T is not known before. At that point the full argument list is known, there is zero variadic arguments. The standard says the following (§17.6.3 (7)):
When N is zero, the instantiation of the expansion produces an empty list. Such an instantiation does not alter the syntactic interpretation of the enclosing construct
This is why I think it is well formed.
What do you think?
How can I track down this ambiguity for sure? It is hard to decide, because the code compiles but it means nothing: §17.7 (8.3) is NDR, the compilers do not have to raise any compilation error.
The code is ill-formed, no diagnostic is required.
If std::is_signed_v<T>, then std::enable_if_t<std::is_signed_v<T>> denotes the type void. Otherwise, std::enable_if_t<std::is_signed_v<T>> does not denote a valid type. Therefore, every valid specialization of myAbs requires an empty template parameter pack.
Per [meta.rqmts]/4, the program has undefined behavior if std::enable_if is specialized. Therefore, the aforementioned behavior cannot be changed.
In my opinion IsSigned< T >... is a dependent template parameter,
therefore it can not be checked against §17.7 (8.3) in template
definition time. IsSigned< T > could be for example void for one
subset of Ts, int for another subset or substitution failure. For
the void subset it is true, that the empty template parameter pack
would be the only valid specialization, but the int subset could
have many valid specializations. It depends on the actual T
argument.
The compiler cannot check it, in the same way it cannot, say, solve an arbitrary equation for you. NDR (no diagnostic required) is made exactly for such cases — the program is ill-formed and would require a diagnostic if the compiler is actually capable of detecting that. NDR permits the compiler not to check it.
When N is zero, the instantiation of the expansion produces an empty
list. Such an instantiation does not alter the syntactic
interpretation of the enclosing construct.
The rule we are talking about is a semantic rule, not a syntactic rule, because syntactic rules are in [gram].
So what is the rationale for the NDR rules? In general, they address problems that are not reproducible among implementation strategies. For example, they may cause the code to misbehave in some implementation strategies, but do not cause any problems (and cannot be easily) in others.
Also, note that the standard talks in terms of program with terms like "ill-formed". Therefore, it is not always plausible to talk about the well-formed ness of an isolated code snippet. In this case, std::enable_if is required not to be specialized, but the situation may get more complicated otherwise.

Why my C++ templated function does not produce `undeclared identified` compile error?

I am trying to create an abstraction about Lights (I'm building a game in C++) and I'm using templates to do that. A part of my code right now is:
// Light.hpp
template <typename LightType>
void LoadLight(GLuint shaderId, const LightType& light, const std::string& glslUniformName)
{
// Load common light attributes
glUniform3f(glGetUniformLocation(lightingShader.GetProgID(), (glslUniformName + ".ambient").c_str()), light.ambient.x, light.ambient.y, light.ambient.z);
glUniform3f(glGetUniformLocation(lightingShader.GetProgID(), (glslUniformName + ".diffuse").c_str()), light.diffuse.x, light.diffuse.y, light.diffuse.z);
glUniform3f(glGetUniformLocation(lightingShader.GetProgID(), (glslUniformName + ".specular").c_str()), light.specular.x, light.specular.y, light.specular.z);
// Load specific light attributes
LoadLightSpecific<LightType>(shaderId, light, glslUniformName); // ???
}
template <typename LightType>
void LoadLightSpecific(GLuint shaderId, const LightType& light, const std::string& glslUniformName);
The specializations for LoadLightSpecific is on a separate .cpp file which is irrelevant with my question.
My problem is in the line with the ???.
I am using LoadLightSpecific before I define it! I thought that this would give me a undeclared identifier (or something like that) compile error but no. It works normally.
Why is that happening? I feel like I am missing something obvious.
Update 23/11/2015
So, as people recommended in comments I used Wandbox to recreate the problem with minimal code. I ended up here. Apparently, the answer to my question seems to be:
"The code should not compile but somehow MSVC works his way around the problem"
It is not unusual with templates that when writing them, you assume something about the template arguments. i.e:
Template<class T>
class C
{
void foo() { T.bar(); }
};
Even though we dont know if T will actually have a method bar(), the compiler accepts it at the moment, because it is just a "template", not actual code. At the time when you instantiate a template, with some arguments, the compiler will check for the correctness of what you assumed, because now it has to generate code.
In the case of functions it is the same. The same logic must apply unless somebody finds an explicit statement about it in the standard, which I tried to find and didn't.
If we follow this logic, when you wrote the template of LoadLight, you assumed that there exists such a function called LoadLightSpecific<T>. In other words,
Why would T.bar() and bar<T>() be accepted in a class template, but not in a function template?
The templated function is not translated at the place of its templated definition, but when it is actually called (similar to the instantiation of a templated class) with some specific template argument. If at that place, all what is needed is available (LoadLightSpecific declared), then it will work fine.
However, I think that it is good practice to, as much as possible, have things declared at the place of the template definition. This will make it easier to track the dependencies.
For this particular code:
If there's a function template called LoadLightSpecific in scope at the point of definition, then this template definition is valid by itself. (It doesn't have to have that signature; even template<int> void LoadLightSpecific(); will do.)
The reason for this is that the compiler must know LoadLightSpecific is a template in order to parse the < as the start of a template argument list, rather than the less-than operator.
Since LoadLightSpecific<LightType>, if parsed as a template-id, is dependent on a template parameter, name lookup for LoadLightSpecific is postponed until instantiation. (Note that this does not mean instantiation will necessarily succeed: a declaration that is not in the template definition context can only be found in the instantiation context by ADL, not by normal unqualified lookup.)
In the more general case, the standard specifies what names are considered dependent on a template parameter and what aren't. Non-dependent names are looked up and bound at the point of template definition:
If a name does not depend on a template-parameter (as defined in
14.6.2), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template
definition; the name is bound to the declaration (or declarations)
found at that point and this binding is not affected by declarations
that are visible at the point of instantiation.
MSVC is well-known for its nonconformance in this area.

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

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
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> {};
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.

Why is this C++ explicit template specialization code illegal?

(Note: I know how it is illegal, I'm looking for the reason that the language make it so.)
template<class c> void Foo(); // Note: no generic version, here or anywhere.
int main(){
Foo<int>();
return 0;
}
template<> void Foo<int>();
Error:
error: explicit specialization of 'Foo<int>' after instantiation
A quick pass with Google found this citation of the spec but that offers only the what and not the why.
Edit:
Several responses have forwarded the argument (e.g. confirmed my speculation) that the rule is this way because to do otherwise would violate the One Definition Rule (ODR). However, this is a very weak argument because it doesn't hold, in this case, for two reaons:
Moving the explicit specialization to another translation unit solves the problem and doesn't seem to violate the ODR (or so the linker says).
The short form of the ODR (as applied to functions) is that you can't have more than one body for any given function, and I don't. The only place the body of the function is ever defined is in the explicit specialization, so the call to Foo<int> can't define a generic specialization of the template because there is no generic body to be specialized.
Speculation on the matter:
A guess as to why the rule exist at all: if the first line offered a definition (as opposed to a declaration), an explicit specialization after an instantiation would be a problem because you would get multiple definitions. But in this case, the only definition in sight is the explicit specialization.
Oddly the following (or something like it in the real code I'm working on) works:
File A:
template<class c> void Foo();
int main(){
Foo<int>();
return 0;
}
File B:
template<class c> void Foo();
template<> void Foo<int>();
But to use that in general starts to create a spaghetti imports structure.
A guess as to why the rule exist at
all: if the first line offered a
definition (as opposed to a
declaration), an explicit
specialization after an instantiation
would be a problem because you would
get multiple definitions. But in this
case, the only definition in sight is
the explicit specialization.
But you do have multiple definitions. You have already defined Foo< int > when you instantiate it and after that you try to specialize the template function for int, which is already defined.
int main(){
Foo<int>(); // Define Foo<int>();
return 0;
}
template<> void Foo<int>(); // Trying to specialize already defined Foo<int>
This code is illegal because explicit specialization appears after the instantiation. Basically, the compiler first saw the generic template, then it saw its instantiation and specialized that generic template with a specific type. After that it saw a specific implementation of the generic template that was already instantiated. So what is the compiler supposed to do? Go back and re-compile the code? That's why it is not allowed to do that.
You have to think of an explicit specialization as a function declaration. Just like if you had two overloaded functions (non-templated), if only one declaration can be found before you try to make a call to the second version, the compiler is going to say that it cannot find the required overloaded version. The difference with templates is that the compiler can generate that specialization based on the general function template. So, why is it forbidden to do this? Because the full template specialization violates the ODR when it is seen, since, by that time, there already exists a template specialization for the same type. When a template is instantiated (implicitly or not), the corresponding template specialization is also created, such that later use (in the same translation unit) of the same specialization will be able to reuse the instantiation and not duplicate the template code for every instantiations. Obviously, the ODR applies just as well to template specializations as it applies elsewhere.
So, when the quoted text says "no diagnostic is required", it just means that the compiler is not required to provide you with the insightful remark that the problem is due to an instantiation of the template occurring sometime before the explicit specialization. But, if it doesn't do that, the other option is to give the standard ODR violation error, i.e., "multiple definitions of 'Foo' specialization for [T = int]" or something like that, which wouldn't be as helpful as the more clever diagnostic.
RESPONSE TO EDIT
1) Although the saying goes that all template function definitions (i.e. implementation) must be visible at the point of instantiation (such that the compiler can substitute the template argument(s) and instantiate the function template). However, implicit instantiation of the function template only requires that the declaration of the function be available. So, in your case, splitting it into two translation units works, because it does not violate ODR (since in that TU, there is only one declaration of Foo<int>), the declaration if Foo<int> is available at the implicit instantiation point (through Foo<T>), and the definition of Foo<int> is available to the linker within TU B. So, no one has argued that this second example is "not supposed to work", it works as it is supposed to. Your question is about a rule that applies within one translation unit, don't counter the arguments by saying that the error doesn't occur when you split it into two TUs (especially when it clearly should work fine in two TUs, according to the rules).
2) In your first example, either there will be an error because the compiler cannot find the general function template (the non-specialized implementation) and thus cannot instantiate Foo<int> from the general template. Or, the compiler will find a definition for the general template, use it to instantiate Foo<int>, and then throw an error because a second template specialization Foo<int> is encountered. You seem to think that the compiler will find your specialization before it gets to it, it doesn't. C++ compilers compile the code from top to bottom, they don't go back and forth to substitute stuff here and there. When the compiler gets to the first use of Foo<int>, it sees only the general template at that point, assumes there will be an implementation of that general template that can be used to instantiate Foo<int>, it is not expecting a specialized implementation for Foo<int>, it is expecting and will use the general one. Then, it sees the specialization and throws the error, because it already had made its mind that the general version was to be used, so, it does see two distinct definitions for the same function, and yes, it does violate ODR. It's as simple as that.
WHY OH WHY!!!
The 2 TU case has to work because you should be able to share template instantiations between TUs, that's a feature of C++, and a useful one (in case when you have a small number of possible instantiations, you can pre-compile them).
The 1 TU case cannot be allowed because declaring something in C++ tells the compiler "there is this thing defined somewhere". You tell the compiler "there is a general definition of the template somewhere", then say "I want to use the general definition to make the function Foo<int>", and finally, you say "whenever Foo<int> is called, it should use this special definition". That's a flat out contradiction! That's why the ODR exists and applies to this context, to forbid such contradictions. It doesn't matter whether the general definition "to-be-found" is not present, the compiler expects it, and it has to assume that it does exist and that it is different from the specialization. It cannot go on and say "ok, so, I'll look everywhere else in the code for the general definition, and if I cannot find it, then I will come back and 'approve' this specialization to be used instead of the general definition, but if I find it I will flag this specialization as an error". Nor can it go on and flatly ignore the desire of the programmer by changing code that clear shows intent to use the general template (since the specialization is not declared yet), for code that uses a specialization that appears later. I can't possibly explain the "why" any more clearly than that.
The 2 TU case is completely different. When the compiler is compiling TU A (that uses Foo<int>), it will look for the general definition, fail to find it, assume that it will be linked-in later as Foo<int>, and leaves a symbol placeholder. Then, since the linker will not look for templates (templates are NOT exportable, in practice), it will look for a function that implements Foo<int>, and it doesn't care whether it is a specialized version or not. The linker is happy as long as it finds the same symbol to link to. This is so, because it would be a nightmare to do it otherwise (look up discussions on "exported templates") for both the programmers (not being able to easily change functions in their compiled libraries) and for the compiler vendors (having to implement this linking crazy scheme).

Why can't templates take function local types?

In C++ it's OK to have a funcction that takes a function local type:
int main() {
struct S { static void M(const S& s) { } };
S s;
S::M(s);
}
but not OK to have a template that does:
template<typename T> void Foo(const T& t) { }
int main() {
struct S { } s;
Foo(s); // Line 5: error: no matching function for call to 'Foo(main()::S&)'
}
14.3.1 paragraph 2 in the c++ standard.
A type with no linkage [...] shall not be used as a template-argument for a template type-parameter
Why does C++ disallow that?
The best explanation I've heard so far it that inner types have no linkage and that this could imply that a function that takes them as an arg must have no linkage. But there is no reason I can see that a template instantiation must have linkage.
p.s. Please don't just say "thats not allowed because the standard says it's not"
I believe the difficulty that was foreseen was with two instantiations of Foo<T> actually meaning entirely different things, because T wasn't the same for both. Quite a few early implementations of templates (including cfront's) used a repository of template instantiations, so the compiler could automatically instantiate a template over a required type when/if it was found that an instantiation over that type wasn't already in the repository.
To make that work with local types, the repository wouldn't just be able to store the type over which the template was instantiated, but instead it would have to do something like creating a complete "path" to the type for the instantiation. While that's probably possible, I think it was seen as a lot of extra work for little (if any) real benefit.
Since then, the rules have changed enough that the compiler is already required to do something that's just about equivalent, finding (and coalescing) instantiations over the same type at different places (including across TUs) so that two instantiations of foo<int> (for example) don't violate the ODR. Based on that realization, the restriction has been loosened in (the current draft of) C++0x (you still can't instantiate a template class over a local type, but you can use a local type as parameter to a template function).
I'm guessing it is because it would require the template to be effectively instantiated within the scope of the function, since that is where such types are visible. However, at the same time, template instantiations are supposed to act as if they are in the scope in which the template is defined. I'm sure this it's possible to deal with that somehow, but if I'm right the standards body decided not to put that burden on compiler writers.
A similar decision was the reason vector<vector<int>> is invalid syntax per the standard; detecting that construction requires some interaction between compiler lexer and parser phases. However, that's changing, because the C++0x standards folk found that all the compilers are detecting it anyway to emit sane error messages.
I suspect that if it were to be demonstrated that allowing this construction was trivial to implement, and that it didn't introduce any ambiguities in the language scoping rules, you might someday see the standard changed here too.