I have GetContainer() function as follows.
template<typename I,typename T,typename Container>
Container& ObjCollection<I,T,Container>::GetContainer()
{
return mContainer;
}
When I use this method as follows
template<typename I,typename T>
T& DynamicObjCollection<I,T>::Insert(T& t)
{
GetContainer().insert(&t);
return t;
}
I got errors.
error: there are no arguments to ‘GetContainer’ that depend on a template parameter,
so a declaration of ‘GetContainer’ must be available
error: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of
an undeclared name is deprecated)
It works fine with MSVC, but g++ is not so permissive. What's wrong with the code?
I noticed that the GetContainer function is a method of ObjCollection, while Insert is a member of DynamicObjectCollection. From this, I'm going to assume that DynamicObjectCollection inherits from ObjectCollection.
If this is indeed the case, the problem is that when you write a template class that inherits from a template base class, the way that name lookup works is slightly different from name lookup in normal classes. In particular, you cannot just reference base class members using their names; you need to indicate to the compiler where to look for the name. The reason this works in Visual Studio is that the Microsoft C++ compiler actually gets this behavior wrong and allows code that is technically illegal to compile just fine.
If you want to invoke the GetContainer function of the base class, you have two options. First, you can explicitly indicate that the call is to a member function:
this->GetContainer().insert(&t);
Now that the compiler knows that GetContainer is a member of DynamicObjectCollection, it knows that it might need to look up GetContainer in the base class, and so it will defer name lookup until the template is instantiated.
The other option available would be to add a using declaration into the class body:
template <typename I, typename T>
class DynamicObjectCollection: public ObjectCollection<I, T, /* ? */> {
public:
using ObjectCollection<I, T, /* ? */>::GetContainer;
/* ... */
};
This also indicates unambiguously to the compiler that GetContainer may be defined in the base class, and so it defers lookup until template instantiation.
If this isn't applicable to your situation, let me know and I can delete this post.
Hope this helps!
Related
I have the following code:
#include <iostream>
template <typename T>
struct Base
{
using Type = int;
};
template <typename T>
struct Derived : Base<T>
{
//uncommmenting the below cause compiler error
//using Alias = Type;
};
int main()
{
Derived<void>::Type b = 1;
std::cout << b << std::endl;
return 0;
}
Now the typename Type is available to Derived if its in a deduced context - as shown by the perfectly valid declaration of b. However, if I try to refer to Type inside the declaration of Derived itself, then I get a compiler error telling me that Type does not name a type (for example if the definition of Alias is uncommented).
I guess this is something to do with the compiler not being able to check whether or not Type can be pulled in from the base class when it is parsing the definition of Derived outside the context of a specific instantiation of parameter T. In this case, this is frustrating, as Base always defines Type irrespective of T. So my question is twofold:
1). Why on Earth does this happen? By this I mean why does the compiler bother parsing Derived at all outside of an instantiation context (I guess non-deduced context), when not doing so would avoid these 'bogus' compiler errors? Perhaps there is a good reason for this. What is the rule in the standard that states this must happen?
2). What is a good workaround for precisely this type of problem? I have a real-life case where I need to use base class types in the definition of a derived class, but am prevented from doing so by this problem. I guess I'm looking for some kind of 'hide behind non-deduced context' solution, where I prevent this compiler 'first-pass' by putting required definitions/typedefs behind templated classes or something along those lines.
EDIT: As some answers below point out, I can use using Alias = typename Base<T>::Type. I should have said from the outset, I'm aware this works. However, its not entirely satisfactory for two reasons: 1) It doesn't use the inheritance hierarchy at all (Derived would not have to be derived from Base for this to work), and I'm precisely trying to use types defined in my base class hierarchy and 2) The real-life case actually has several layers of inheritance. If I wanted to pull in something from several layers up this becomes really quite ugly (I either need to refer to a non-direct ancestor, or else repeat the using at every layer until I reach the one I need it at)
Because type is in a "dependent scope" you can access it like this:
typename Base<T>::Type
Your Alias should then be defined like this:
using Alias = typename Base<T>::Type;
Note that the compiler doesn't, at this point, know if Base<T>::type describes a member variable or a nested type, that is why the keyword typename is required.
Layers
You do not need to repeat the definition at every layer, here is an example, link:
template <typename T>
struct intermediate : Base<T>
{
// using Type = typename Base<T>::Type; // Not needed
};
template <typename T>
struct Derived : intermediate<T>
{
using Type = typename intermediate<T>::Type;
};
Update
You could also use the class it self, this relies on using an unknown specializations.
template <typename T>
struct Derived : Base<T>
{
using Type = typename Derived::Type; // <T> not required here.
};
The problem is that Base<T> is a dependent base class, and there may be specializations for it in which Type is not anymore defined. Say for example you have a specialization like
template<>
class Base<int>
{}; // there's no more Type here
The compiler cannot know this in advance (technically it cannot know until the instantiation of the template), especially if the specialization is defined in a different translation unit. So, the language designers chose to take the easy route: whenever you refer to something that's dependent, you need to explicitly specifify this, like in your case
using Alias = typename Base<T>::Type;
I guess this is something to do with the compiler not being able to check whether or not Type can be pulled in from the base class when it is parsing the definition of Derived outside the context of a specific instantiation of parameter T.
Yes.
In this case, this is frustrating, as Base always defines Type irrespective of T.
Yes.
But in general it would be entirely infeasible to detect whether this were true, and extremely confusing if the semantics of the language changed when it were true.
Perhaps there is a good reason for this.
C++ is a general-purpose programming language, not an optimised-for-the-program-Smeeheey-is-working-on-today programming language. :)
What is the rule in the standard that states this must happen?
It's this:
[C++14: 14.6.2/3]: In the definition of a class or class template, if a base class depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member. [..]
What is a good workaround for precisely this type of problem?
You already know — qualification:
using Alias = typename Base<T>::Type;
When defining a template, sometimes things need to be a bit more explicit:
using Alias = typename Base<T>::Type;
Rougly speaking: a template is a blueprint of sorts. Nothing actually exists until the template get instantiated.
When doing the same thing, but in a non-template context, a C++ compiler will try to figure out what Type is. It'll try to find it in the base classes, and go from there. Because everything is already declared, and things are pretty much cut-and-dry.
Here, a base class does not really exist until the template gets instantiated. If you already know about template specialization, that you should realize that the base class may not actually turn out to have a Type member, when the template gets instantiated if there's a specialization for the base class defined later down the road, that's going to override the whole thing, and turn it inside and out.
As such, when encountering just a plain, old, Type in this context, the compiler can't make a lot of assumptions. It can't assume that it can look in any defined template base classes because those base classes may not actually look anything like the compiler thinks they will look, when things start to solidify; so you have spell everything out, explicitly, for the compiler, and tell the compiler exactly what your are trying to do, here.
You cannot use your base class types in a non-deduced context. C++ refuses to assume unbound names refer to things in your base class.
template <typename T>
struct Base {
using Type = int;
};
template<>
struct Base<int> {};
using Type=std::string;
template <typename T>
struct Derived : Base<T> {
using Alias = Type;
};
Now let us look at what is going on here. Type is visible in Derived -- a global one. Should Derived use that or not?
Under the rule of "parse nothing until instantiated", we use the global Type if and only if T is int, due to the Base specialization that removes Type from it.
Following that rule we run into the problem that we can diagnose basically no errors in the template prior to it being instantiated, because the base class could replace the meaning of almost anything! Call abs? Could be a member of the parent! Mention a type? Could be from the parent!
That would force templates to basically be macros; no meaningful parsing could be done prior to instantiating them. Minor typos could result in massively different behavior. Almost any incorrectness in a template would be impossible to diagnose without creating test instances.
Having templates that can be checked for correctness means that when you want to use your parent class types and members, you have to say you are doing so.
As a partial response about the point
[T]his is frustrating, as Base always defines Type irrespective of T.
I'd say: no it does not.
Please consider the following example differing from yours only by the one line definition of Base<void> and of the definition of Alias:
#include <iostream>
template <typename T>
struct Base
{
using Type = int;
};
template <typename T>
struct Derived : Base<T>
{
using Alias = typename Base<T>::Type; // error: no type named 'Type' in 'struct Base<void>'
};
template<> struct Base<void> {};
int main()
{
Derived<void>::Type b = 1;
std::cout << b << std::endl;
return 0;
}
In the context of template <typename T> struct Derived : Base<T>, there is no guaranty that Type exists. You must explicitly tell your compiler than Base<T>::Type is a type (with typename) and if you ever fail this contract, you'll end up with a compilation error.
I am using g++ compiler. I wrote the following code which has a template class definition. The class has a struct data-type called node which has elements a and b of the generic type. The class has one function called print which prints p.h where p is a variable of type node of the class object. The compiler does not show any errors although 'h' is not an element of struct node. Why is that?
#include<iostream>
#include<cstdlib>
using namespace std;
template <typename e>
class mc
{
typedef struct node
{
e a,b;
}node;
node p;
public:
void print();
};
template <typename e>
void mc<e>::print()
{
std::cout<<p.h;
}
int main()
{
mc<int> m;
//m.print();
return(0);
}
The compiler shows an error only when m.print() is uncommented in main. Why is that?
If you donot use the object (instance) of a template, compiler only check the logic of the template. The template will not be instantiated. But if you try to use a instance of a template, that template will be instantiated (expanded) then you will see the error that h is not a member of p.
That is to say that , if you comment out //m.print(), the template will be instantiated.
In order to make writing template classes a bit easier, non-invoked template methods are not instantiated.
A few things are checked -- the signature of the method, and it does lookup of any methods or functions that involve only data non-dependent on the template parameters of the class and the like.
In this case, p is technically dependent on the template parameters of the class, so the check that p.h is valid is done at instantiation. Now, you could prove that there is no e such that p.h is valid, but the compiler doesn't have to, so it doesn't bother.
The program may still be ill-formed: there are clauses in the standard where programs can be ill-formed (no diagnostic required) if there are no valid specializations of a template, but I do not know if that applies to a method of a template or not.
Once you invoke print, the method is instantiated, and the error is noticed.
An example of where this is used in the std library is vector -- a number of its methods, including <, blinding invoke < on its data. vector does not require that its data support <, but it does require it if anyone tries to call <.
Modern C++ techniques would involve disabling vector::operator< in that case (the standard talks about "does not participate in overload resolution"), and in C++1z this becomes far easier via requires clauses (if that proposal ever gets standardized).
Considering the following code:
template<typename T>
struct A
{
void f(){...}
friend T;
};
template<typename T>
struct B
{
void f(T){...}//code depends on T
void g(){...}//code doesn't depends on T
}
As you see, the "code" in the struct A doesn't depend on T.
Will the compiler generate different code in the final binary for every T used to instantiate A?
Same question for B::g() function, will the compiler use the same function for all instances of B<T> when it's possible, for example this is not used in g(), so no dependency on T? Does the standard have any specification for this case?
If you want to be sure what the compiler generates, why not write a non-template struct implementing the code that doesn't depend on T, and then derive your template from the non-template? You get one copy of the non-template code, which each instance of the template inherits.
At least, that's what I've done in the past when I found that template instantiation was making my compiled objects very large.
Where do I have to specify default template parameters of classes member functions (assuming that the declaration is (of course) in the "class body", and the function definition is outside the class body) for each case in C++2011 :
"normal" functions
static functions
friend functions
In the definition, in the declaration or both ?
Well,
From my experiences creating template classes and methods, you specify a template function as such:
template<typename T>
T MyFunc(T &aArg1, T &aArg2)
{
//...Definition Goes Here
}
The typename T is the template argument type for the template function and you need to pass that data type consistently to each argument labeled as "T". This means that aArg2 has to be whatever data type aArg1 is. Now, when you call this function, you call it like so:
MyFunc</*datatype*/int>(iArg1, iArg2); the two arguments have to be data type "int" or you'll get a warning or an error.
Now, this also applies to class methods (I think that is what you meant by "classes member functions") which are the functions supplied by the class (i.e. MyClass::MyFunc()) so when you declare a class method that is a template method, you do it in the same manner. Here is an example class:
class MyClass
{
MyClass();
~MyClass();
template<typename T>
static T MyStaticFunc(T aArg) { return aArg; }
template<typename T>
T MyFunc(T aArg) { return aArg; }
}
As you can see, not to difficult. Now, static functions are the same way you just have to be sure t define then in the same module that the class is built in, otherwise, you'll get an error.
Unfortunately, I never really use "friend" methods, so I don't know how to tackle that. I would suspect you would do it in the same way as the other two. I hoped that whole essay of an answer helped.
Trying these out in Clang suggests the following:
For non-static and static functions, specifying the default in either the definition or
the declaration is acceptable - but not both and certainly not if
they contradict one another;
For friend functions, specifying a
default inside the class definition results in an error.
I have a class MyClass which is templated on typename T. But inside, I want a method which is templated on another type TT (which is unrelated to T).
After reading/tinkering, I found the following notation:
template <typename T>
class MyClass
{
public :
template<typename TT>
void MyMethod(const TT & param) ;
} ;
For stylistic reasons (I like to have my templated class declaration in one header file, and the method definitions in another header file), I won't define the method inside the class declaration. So, I have to write it as:
template <typename T> // this is the type of the class
template <typename TT> // this is the type of the method
void MyClass<T>::MyMethod(const TT & param)
{
// etc.
}
I knew I had to "declare" the typenames used in the method, but didn't know how exactly, and found through trials and errors.
The code above compiles on Visual C++ 2008, but: Is this the correct way to have a method templated on TT inside a class templated on T?
As a bonus: Are there hidden problems/surprises/constraints behind this kind of code? (I guess the specializations can be quite amusing to write)
This is indeed the correct way of doing what you want to do, and it will work on every decent C++ compiler. I tested it on gcc4.4 and the latest clang release.
There are problems/surprises/constraints behind any kind of code.
The major issue you could eventually run in with this code is that you can't make a templated function virtual, so if you want to get polymorphism at the class level for your templated function, you're off implementing it with an external function.
I think It's OK to do that. Take a look for example at std::vector implementation. You have class vector, which has a few template parameters (most notably an element type), and inside, one of its constructors is declared in similar way as your method. It has InputIterator as a template parameter. So I think that this is not so uncommon practice.