I recently attempted to create an is_class class and needed a way for the compiler to differentiate between enumeration types and class types for which conversion operators are defined. Seeing as how classes, structs and unions are the only types compatible with pointer-to-member functions, I decided to have the compiler determine if the type used to instantiate the is_class template was, in turn, compatible with pointers-to-member functions. After running into several issues, I decided to test the behavior of enumerations when used in conjunction with pointer-to-members and got some wacky results. The following segment illustrates the first quirk:
enum ENUM {};
void Test(void (ENUM::*pmem) (void))
{
/* ... */
}
Test(NULL);
When compiling with Microsoft Visual C++ 2010, the pointer-to-member portion of the function definition: (ENUM::*pmem)
is highlighted in red and mousing over the declaration reveals the error:
Error: "ENUM" is not a class type
However, the compiler parses this segment without encountering any errors, assigning pmem to NULL. It is interesting to me that the compiler would allow this seeing as how enumeration types are not classes, structs or unions and therefore cannot possess methods of their own.
The second point of interest arose when creating a template function, taking a pointer-to-member argument whose type varies:
template<class _Ty>
void Test_Template(void (_Ty::*pmem) (void))
{
/* ... */
}
Of course in order to use this function, it must be explicitly qualified:
Test_Template<ENUM>(NULL);
This call however, generates an error stating:
invalid explicit template argument(s) for 'void Test(void (__thiscall _Ty::* )(void))'
I fixed this issue by creating an additional function template, the prototype of which would match any call that failed to match the prototype for the former template function (which involved using an ellipsis).
Questions:
Why is an enumeration compatible with pointers-to-members?
Why is there an exact match when invoking the non-template Test function while the compiler generates an error for the template Test_Template explicit qualification?
With regards to your first question, it seems like the compiler is indeed reporting that enums can't have member functions, since the compiler is reporting an error on the function declaration. It's probably letting the call succeed by internally trying to correct the bad declaration as much as possible, which in this case means noticing that you were trying to declare something pointer-like and allowing the call. There's no requirement that the compiler give you an error on that line; since the program is I'll-formed, as long as the compiler rejects the program with a diagnostic it doesn't need to give errors everywhere.
As for your second question, the reason that having a second template makes the error go away is the "substitution failure is not an error" (SFINAE) principle. When the compiler instantiates a function template with some type arguments, if it finds that a particular function instantiation is invalid (for example, trying to get a pointer to a member of an enum), it doesn't report an error. Instead, it just removes that template from consideration. If, however, none of the templates you've written are valid when instantiated with the given arguments, then the compiler will issue am error because it can't find a match for what you're trying to do. In the first case, when you have just one template, the error occurs because SFINAE eliminates the only template candidate from consideration, causing the template instantition to have no matching template. In the second case, your "catch-all" template is still valid after you instantiate the template, so while the template taking a pointer-to-member is excluded, there is still a legal template that you can refer to. Consequently, the code is perfectly fine.
Related
What does it mean that compiler is using two phase lookup in order to compile template class?
Templates are compiled (at least) twice:
Without Instantiation the template code itself is checked for syntax.
Eg: Any syntax errors such as ; etc.
At the time of instantiation(when the exact type is known), the template code is checked again to ensure all calls are valid for that particular type.
Eg: The template might in turn call to functions which might not be present for that particular type.
This is called as Two Phase Lookup.
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.
Consider the following code:
#include <iostream>
void f(int) { }
void f(int, short) { }
template<typename... Ts> void g(void (*)(Ts...))
{
std::cout << sizeof...(Ts) << '\n';
}
template<typename T, typename... Ts> void h(void (*)(T, Ts...))
{
std::cout << sizeof...(Ts) << '\n';
}
int main()
{
g(f); // #1
g<int>(f); // #2
h(f); // #3
h<int>(f); // #4
}
The intent is to try each of the lines in the body of main() separately. My expectations were that all four calls were ambiguous and would result in compiler errors.
I tested the code on:
Clang 3.6.0 and GCC 4.9.2, both using -Wall -Wextra -pedantic -std=c++14 (-std=c++1y for GCC) - same behaviour in all these cases, except for minor differences in the wording of error messages;
Visual C++ 2013 Update 4 and Visual C++ 2015 CTP6 - again, same behaviour, so I'll call them "MSVC" going forward.
Clang and GCC:
#1: Compiler error, with a confusing message, basically no overload of 'f' matching 'void (*)()'. What? Where did the no-param declaration come from?
#3: Compiler error, with another confusing message: couldn't infer template argument 'T'. Of all the things that could fail there, deducing the argument for T would be the last one I would expect...
#2 and #4: Compiles with no errors and no warnings, and chooses the first overload.
For all four cases, if we eliminate one of the overloads (any one), the code compiles fine and chooses the remaining function. This looks like an inconsistency in Clang and GCC: after all, if deduction succeeds for both overloads separately, how can one be chosen over the other in cases #2 and #4? Aren't they both perfect matches?
Now, MSVC:
#1, #3 and #4: Compiler error, with a nice message: cannot deduce template argument as function argument is ambiguous. Now that's what I'm talking about! But, wait...
#2: Compiles with no errors and no warnings, and chooses the first overload. Trying the two overloads separately, only the first one matches. The second one generates an error: cannot convert argument 1 from 'void (*)(int,short)' to 'void (*)(int)'. Not so good anymore.
To clarify what I'm looking for with case #2, this is what the standard (N4296, first draft after C++14 final) says in [14.8.1p9]:
Template argument deduction can extend the sequence of template
arguments corresponding to a template parameter pack, even when the
sequence contains explicitly specified template arguments.
Looks like this part doesn't quite work in MSVC, making it choose the first overload for #2.
So far, it looks like MSVC, while not quite right, is at least relatively consistent. What's going on with Clang and GCC? What's the correct behaviour according to the standard for each case?
As far as I can tell, Clang and GCC are right in all four cases according to the standard, even though their behaviour may seem counter-intuitive, especially in cases #2 and #4.
There are two main steps in the analysis of the function calls in the code sample. The first one is template argument deduction and substitution. When that completes, it yields a declaration of a specialization (of either g or h) where all template parameters have been replaced with actual types.
Then, the second step attempts to match f's overloads against the actual pointer-to-function parameter that was constructed in the previous step. The best match is chosen according to the rules in [13.4] - Address of overloaded function; in our cases this is pretty simple, as there are no templates among the overloads, so we have either one perfect match or none at all.
The key point to understanding what happens here is that an ambiguity in the first step doesn't necessarily mean that the whole process fails.
The quotes below are from N4296 but the content hasn't changed since C++11.
[14.8.2.1p6] describes the process of template argument deduction when a function parameter is a pointer to function (emphasis mine):
When P is a function type, pointer to function type, or pointer to
member function type:
— If the argument is an overload set containing one or more function
templates, the parameter is treated as a non-deduced context.
— If the argument is an overload set (not
containing function templates), trial argument deduction is attempted
using each of the members of the set. If deduction succeeds for only
one of the overload set members, that member is used as the argument
value for the deduction. If deduction succeeds for more than one
member of the overload set the parameter is treated as a non-deduced
context.
For completeness, [14.8.2.5p5] clarifies that the same rule applies even when there's no match:
The non-deduced contexts are: [...]
— A function parameter for which argument deduction cannot be done because
the associated function argument is a function, or a set of overloaded
functions (13.4), and one or more of the following apply:
— more than one function matches
the function parameter type (resulting in an ambiguous deduction), or
— no function matches the function parameter type, or
— the set of functions supplied as an argument contains one or more
function templates.
So, no hard errors because of ambiguity in these cases. Instead, all template parameters are in non-deduced contexts in all our cases. This combines with [14.8.1p3]:
[...] A trailing template parameter pack (14.5.3) not otherwise
deduced will be deduced to an empty sequence of template arguments.
[...]
While the use of the word "deduced" is confusing here, I take this to mean that a template parameter pack is set to the empty sequence if no elements can be deduced for it from any source and there are no template arguments explicitly specified for it.
Now, the error messages from Clang and GCC start to make sense (an error message that only makes sense after you understand why the error occurs is not exactly the definition of a helpful error message, but I guess it's better than nothing):
#1: Since Ts is the empty sequence, the parameter of g's specialization is indeed void (*)() in this case. The compiler then tries to match one of the overloads to the destination type and fails.
#3: T only appears in a non-deduced context and is not explicitly specified (and it's not a parameter pack, so it cannot be "empty"), so a specialization declaration cannot be constructed for h, hence the message.
For the cases that do compile:
#2: Ts cannot be deduced, but one template parameter is explicitly specified for it, so Ts is int, making g's specialization's parameter void (*)(int). The overloads are then matched against this destination type, and the first one is chosen.
#4: T is explicitly specified as int and Ts is the empty sequence, so h's specialization's parameter is void (*)(int), the same as above.
When we eliminate one of the overloads, we eliminate the ambiguity during template argument deduction, so the template parameters are no longer in non-deduced contexts, allowing them to be deduced according to the remaining overload.
A quick verification is that adding a third overload
void f() { }
allows case #1 to compile, which is consistent with all of the above.
I suppose things were specified this way to allow template arguments involved in pointer-to-function parameters to be obtained from other sources, like other function arguments or explicitly-specified template arguments, even when template argument deduction can't be done based on the pointer-to-function parameter itself. This allows a function template specialization declaration to be constructed in more cases. Since the overloads are then matched against the parameter of the synthesized specialization, this means we have a way to select an overload even if template argument deduction is ambiguous. Quite useful if this is what you're after, terribly confusing in some other cases - nothing unusual, really.
The funny thing is that MSVC's error message, while apparently nice and helpful, is actually misleading for #1, somewhat but not quite helpful for #3, and incorrect for #4. Also, its behaviour for #2 is a side effect of a separate problem in its implementation, as explained in the question; if it weren't for that, it would probably issue the same incorrect error message for #2 as well.
This is not to say that I like Clang's and GCC's error messages for #1 and #3; I think they should at least include a note about the non-deduced context and the reason it occurs.
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).
I have a class that is defined as the following:
template <class WidgetType>
class CometWidget : public WidgetType;
Inside a function I am doing this:
dynamic_cast<CometWidget *>(iter2->second.second)->changesCommited_();
and it resolves the CometWidget type, complies and run correctly.
The code runs inside the CometWidget class.
How on earth does this happen?
Why is that so? Should it even compile?
If it's inside the declaration of CometWidget then you don't need to explicitly qualify the template (or whatever term you use to say CometWidget<...>).
Very interesting indeed. It seems to me like an interesting compiler bug.
It is possible to deduce the correct argument of the CometWidget<> template - just the same way you can deduce template parameters of a function from argument list. If it would be static cast, it would be less surprising.
With dynamic cast, there's little expected to be in common between the source and the target type. So, such "guessing" might have occurred, but then it's not a rightful one.
What compiler is this?