Template deduction in dynamic_cast - c++

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?

Related

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.

Automatic template deduction when lhs reference is used

I was wondering if I write something like this:
Type &var = database.get<TYPE>(name);
Assuming that database is a container able to store datablocks of different datatypes. To get a reference to that datablock, the name as std::string is passed to get() so that at different places with that call I have a way to access certain 'global' variables. I have get() as a template method and I would like to keep it that way.
What I want to do is shorten that call an elegant way like this:
Type &var = database.get(name);
So the template deduction is automatically performed. Now I could create a macro for that, but this is not what I want to do, as I do not consider it elegant for such case.
That deduction though does not work, because we need a template parameter. Why can't the compiler take what is set for the variable and pass it as template parameter automatically? Is there a way to do this? I don't want to have any type conversions in this case. Can we omit it?
No, you can't do this---the rules of the language simply don't allow the compiler to take into account the declared type of var in order to perform the deduction. (Note that template arguments for a function template can be deduced when initializing a function pointer by taking the address of a function template. However, that's not what's happening in this case.)
However, you can easily avoid writing the type twice or inducing any undesirable conversions, by using auto:
auto& var = database.get<Type>(name);
Sorry, this is not possible. What you are trying to do is to have the return type of a templated function based on the value of its parameter.
This cannot work.
Automatic template deduction (like you mentioned) can only be performed, if the template parameter is obvious. For example:
template<_T> void func(_T param) { }
This can be called like
int a;
func(a); //instead of func<int>(a);
here the compiler knows exactly what you are trying to do.
Because all templates are resolved at compile time, there is no way of changig a methods return type based on any vague arguments.
You could have a look at boost::any, which does your Job quite well.

C++ std::vector with pointers to a template class

In a project I am working on I am tying to make a vector with pointers to a template class.
template <typename T>
std::vector<templateClass<T>*> vec;
However, this gives me two errors:
Error C2133: vec : unknown size
Error C2998: std::vector<templateClass<T>*> vec : cannot be a template definition
If I change the code to:
std::vector<templateClass<int>*> vec;
It works fine, so I guess the problem isn't that you cant use template classes with vectors, but that you need to tell the compiler what type to use. Is there any way around this?
When you create a class instance you have to choose the type. In the definition you can write T but at the moment of create instance you have to specify the type.
So if you want define and not creating an instance use typedef.
You can't have a templated member.
The template must come from the class or function templated declaration.
template <typename T>
class blah {
std::vector<templateClass<T>*> vec;
}
The compiler needs the templated typename to be defined somewhere in the code, for example: blah<int>
If you'd have a templated member, you couldn't define the type anywhere in the code, and the compiler wouldn't be able to decide the member's type.
The templated typename is decided when you first use the function or class (either explicitly or implicitly) so you'd have to have the template definition and implementation somewhere that is accessible by the calling code.
It looks like you are trying to define a new type vec<T> as a shortcut to the longer templetized expression. Normally, this would be done with a typedef, however C++ does not support templetized typedefs.
Note, that in the current code you are essentially trying to define a variable called vec, but you are not giving it a specific type for T and that's why the compiler is complaining.
Currently C++ doesn’t support template typedefs so you have to use the most common solution, proposed by Herb Sutter (http://gotw.ca/gotw/079.htm)

Enumerations and pointer-to-members

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.

iphone compiler inherited templated base classes with passed through type not being expanded in time (just look)

Try this out:
template <typename T>
class Base
{
public:
int someBaseMember;
};
template <typename T>
class Test: public Base<T>
{
public:
void testFunc()
{
someBaseMember = 0;
}
};
In vc++ and the psp compiler (and any other compiler I've encountered) the above will work fine, with the iphone compiler (for device, gcc 4.2 I think, with the -fpermissive flag set) I get an error saying
'someBaseMember is not defined'
on the
'someBaseMember = 0;'
line
The iphone compiler seems to be 'parsing' templated code a lot sooner than other compilers do, (from what I can tell, most others don't even syntax check them until you actually CALL the function, or instantiate an instance.)
From what I can tell its parsing it so soon that it hasn't even parsed the base class yet :S its like it doesn't exist.
Any Ideas?
The error that you are getting is correct (the other compilers should not accept the code and are doing so erroneously); the variable someBaseMember depends on the template instantation of Base<T>, but this dependence has not been expressed in your usage, and hence the compiler is correct in attempting to resolve it independently of the template parameter.
You can resolve this problem by making this dependence explicit, thereby forcing the compiler to resolve the variable using the template instantation. You can use either of the following:
this->someBaseMember = 0;
OR
Base<T>::someBaseMember = 0;
Either of the above should result in the resolution mechanism you want.
EDIT
You might want to see the relevant section of the C++ FAQ Lite:
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.19
http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18
someBaseMember is a name that doesn't seem to depend on the template parameters, so it's not a dependent name, as the standard calls it.
The C++ name lookup rules cause the compiler to not look in the templated base class for this name, since it's not a dependent name. To work around this, you can use this-> to make clear that someBaseMember is a member of the class (and so implicitly dependent on the template parameters):
this->someBaseMember = 0;
This is not specific to the iphone compiler, but defined like that in the language. See also this entry in the C++ FAQ Lite for more details.