Is there any scope problem in this program?
#include<iostream>
using namespace std;
template<class Type>
class Base
{
public:
Type member;
Base(Type param): member(param){
}
};
template<class Type>
class Derived: public Base<Type>
{
public:
Derived(Type param):Base<Type>(param){
// ^
// |_______ Not writing Type here gives error, why?
}
void display()
{
cout << member; /** ERROR HERE **/
}
};
int main()
{
Derived<int> p(5);
p.display();
return 0;
}
I get error 'member' was not declared in this scope. How to fix the problems?
Your question is somewhat confusing. At first I thought you were asking about base<Type> in the member initialization list, then I thought you were asking about accessing member, then back to the first... Now I'm thinking you're asking both, so I'll answer both.
Not writing Type here gives error, why?
When you use a class template's name (my_class_templ), it refers to the template, which is not a type. In order to use it as a type, you need to provide template parameters (my_class_templ<int>, my_class_templ<T>). So wherever a type name is needed (and that includes the base class names in an initialization list), you need to provide template parameters.
You can omit the template parameter list for class templates names within the class template's definition. For example, a copy constructor can be declared as
my_class_templ(const my_class_templ& rhs);
instead of
my_class_templ<T>(const my_class_templ<T>& rhs);
This is just a little syntactic sugar, allowing you to type less.
However, outside of the class templates definition, you need to explicitly spell out all the template parameters. This is also true for derived classes:
my_dervied_class_templ(const my_derived_class_templ& rhs)
: my_class_templ<T>(rhs) // need to spell out <T> here
{
}
I get error 'member' was not declared in this scope. How to fix the problems?
When your template is encountered first by the compiler, there's only its definition and no instantiations have been seen by the compiler yet. The compiler doesn't know whether, at a point of instantiation, there might be specializations of the template in scope or not. However, you could specialize your template for Base<T>::member to refer to something else or not to be defined entirely. (Say, a specialization Base<void> doesn't have a data member.) Therefore, the compiler must not speculate about the members of Base. Consequentially, they will not be looked up in Derived.
The result of this is that, if you need to refer to one of the members of Base, you need to tell the compiler that you expect a Base<T> to have such a member. This is done by fully qualifying its name: Base<Type>::member.
Not writing Type here gives error, why?
If you omit Type there is no way for the compiler to decide whether Base is a base class or is it a member of Derived. Specifying Type makes sure that Base is a template class [base class].
'member' was not declared in this scope
This is something to do with the rules for name lookup (dependent base classes).
C++03 [Section 14.6/8] says
When looking for the declaration of a name used in a template definition, the usual lookup rules (3.4.1, 3.4.2) are used for nondependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known (14.6.2).
Now Section 14.6.2/3 says
In the definition of a class template or a member of a class template, if a base class of the class template 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.
member is an unqualified name so the base class is not examined.
So you have two options.
Use fully qualified name of Member i.e Base<Type>::member
Use this->member.
At the point where the compiler reads the template (not when it instanciates it), it cannot tell what Base<Type> is (it could be specialized), and therefore doesn't attempt to deduce it has a member member. You have to explicitely tell it: cout << this->Base<Type>::member;.
I think (check it, I'm not sure) that a using Base<Type>::member at class scope works too.
The C++ standard requires a compiler to do a "two phase lookup" for templates. That is, they are trying to resolve all non-dependent names (names that don't depend on template parameters) in the first phase when the template is parsed and all the dependent names in the second phase when the template is instantiated.
If you don't qualify member it is treated as a non-dependent name and lookup fails in the first phase. You can solve this by prepending this-> to it. This makes member a dependent name and lookup is delayed until you actually instantiate the template.
Derived(Type param):Base<Type>(param){
That Base<Type> is required because the base of Derived is Base<T>. There is nothing called Base.
void display()
{
//cout << member; /** ERROR HERE **/
cout << this->member;
cout << this>Base<Type>::member;
}
Alternatively having a using declaration in the scope of 'Derived' is also a valid technique.
Related
I am learning templates in C++. So reading examples from different sources(including SO). One such example whose statement i am unable to understand(or rather i think is incorrect) is given below:
class Base {
protected:
template <typename T1>
void print_pi() {
std::cout << (T1)3.141596 << std::endl;
};
};
template <typename T2>
class Derived : public Base {
};
template <typename T3>
class DoubleDerived : public Derived<T3> {
public:
void test() {
print_pi<int>(); // This creates error, however changing to Base::print_pi<int>(); works.
}
};
The user of the accepted answer says:
In the class Derived the name print_pi is a dependent name.
My question is that isn't print_pi a non-dependent name? I mean it doesn't doesn't depends on a template parameter. For instance, print_pi<T> is a dependent name but in OP's code inside the derived class DoubleDerived the name print_pi is non-dependent IMO. Can someone tell me why the user says that print_pi is a dependent name. I mean even print_pi<int> is non-dependent. I was thinking of writing an answer there saying that print_pi is a non-dependent name and according to Non-dependent name lookup members, the problem is that the compiler does not look in dependent base classes when looking up nondependent names but then some people closed the question.
Am i right in saying that the currently accepted answer is incorrect in saying that print_pi is a dependent name?
My question is that isn't print_pi a non-dependent name?
As written, print_pi<int> is a non-dependent name, so according to cppreference
For a non-dependent name used in a template definition, unqualified name lookup takes place when the template definition is examined.
We cannot look into base class (which is template), and no (template) function print_pi exist in global scope. So the compilation error.
Base::print_pi<int>(); is also not dependent. qualified name takes place:
If the lookup of the left hand side name comes up with a class/struct or union name, the name on the right hand side of :: is looked up in the scope of that class (and so may find a declaration of a member of that class or of its base), with the following exceptions [..]
Notice that it is not yet checked that Base is really a base of the class (Demo).
It would be done once the method would be instantiated (Demo)
this->template print_pi<int>();/Derived<T3>::template print_pi<int>(); are dependent. and so, from cppreference
For a dependent name used in a template definition, the lookup is postponed until the template arguments are known
So print_pi<int>() can be found in base classes (if present Demo (else error happens Demo)).
This code compiles with MSVC 2015, but doesn't compile with Clang 5.0.0 (trunk 304874):
template <typename T>
struct Base
{
T data;
};
template <typename T>
struct Derived : Base<T>
{
auto getData() const
{
return data;
}
};
Replacing data with this->data in Derived::getdata() makes Clang happy.
Which compiler is correct according to the C++ standard?
Must this-> be used in template code to access an identifier of a base class?
Clang is correct.
$17.6.2/3 Dependent names [temp.dep]
In the definition of a class or class template, the scope of a dependent base class 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.
For return data;, data is unqualified, then unqualified name lookup will be employed. This means the name in the base class Base<T> (which is a dependent base class because it depends on the template parameter T) shouldn't be found; i.e. the non-dependent names are not looked up in dependent base classes.
this->data or Base<T>::data makes it qualified. This means the name will be looked up at the time of instantiation, and at that time the exact base specialization that must be explored will be known.
Yes, it is. Basically data depends on T.
There is a mechanism called two-phase lookup. Non-(template)dependent names are resolved immediately - at the point of definition. Your data does not exist yet, because Base<T> does not exist yet, as it was not instantiated. Thus, it complains that data is not found.
You need to hint compiler that data depends on the template, and the name lookup should be performed in the second phase, after template parameters are substituted, i.e. template class was instantiated. This can be done by using this or providing template dependent scope.
So, either this->f() or Base<T>::f() will work.
This code compiles with MSVC 2015, but doesn't compile with Clang 5.0.0 (trunk 304874):
template <typename T>
struct Base
{
T data;
};
template <typename T>
struct Derived : Base<T>
{
auto getData() const
{
return data;
}
};
Replacing data with this->data in Derived::getdata() makes Clang happy.
Which compiler is correct according to the C++ standard?
Must this-> be used in template code to access an identifier of a base class?
Clang is correct.
$17.6.2/3 Dependent names [temp.dep]
In the definition of a class or class template, the scope of a dependent base class 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.
For return data;, data is unqualified, then unqualified name lookup will be employed. This means the name in the base class Base<T> (which is a dependent base class because it depends on the template parameter T) shouldn't be found; i.e. the non-dependent names are not looked up in dependent base classes.
this->data or Base<T>::data makes it qualified. This means the name will be looked up at the time of instantiation, and at that time the exact base specialization that must be explored will be known.
Yes, it is. Basically data depends on T.
There is a mechanism called two-phase lookup. Non-(template)dependent names are resolved immediately - at the point of definition. Your data does not exist yet, because Base<T> does not exist yet, as it was not instantiated. Thus, it complains that data is not found.
You need to hint compiler that data depends on the template, and the name lookup should be performed in the second phase, after template parameters are substituted, i.e. template class was instantiated. This can be done by using this or providing template dependent scope.
So, either this->f() or Base<T>::f() will work.
I am working on porting a project from C# to C++ and am having an issue when using templates, I need to have both a non-templated and a templated version of a class with one parented to another, ie:
class DataBuffer // Holds generic databuffer functions (getting size in bytes etc)
{
public:
int32 getVal() { return 10; }
};
template <typename T>
class DataBuffer<T> : public DataBuffer // Able to retrieve data as a type...
{
public:
int32 getSizeOfT() { return sizeof(T); }
};
I have methods that accept any type of DataBuffer as a parameter, so templating the entire class is not possible, is there any way of doing this without renaming the base class?
Any help would be greatly appreciated.
EDIT:
This code does not compile, and throws the following error at compile time:
error C2989: 'DataBuffer' : class template has already been declared as a non-class template
Unfortunately, there is no way of doing so. I think the relevant portion of the standard is:
A class template shall not have the same name as any other template,
class, function, object, enumeration, enumerator, namespace, or type
in the same scope (3.3), except as specified in (14.5.4). Except that
a function template can be overloaded either by (non-template)
functions with the same name or by other function templates with the
same name (14.8.3), a template name declared in namespace scope or in
class scope shall be unique in that scope.
However, the methods that should accept every type of DataBuffer could be made template too, so that inheriting from a common base would become unnecessary.
As the error says, a class template can't have the same name as a non-template.
You will have to rename either the base class or the template.
You'll need to give the class and the class template different names or put them into different namespaces: classes and class templates cannot have exactly the same name.
Currently I have a frustrating problem with forward declaration and template function. I have been trying to googling and do some modification but nothing has worked so far. Below is the snippet of the code:
class TaskScheduler; --> //forward declaration of ‘struct TaskScheduler’
//
//
class TaskEvent {
//
//
};
class HostTask {
//
//
};
template<class T> inline HostTask*
findT(TaskScheduler* tss, T* e)
{
map<int, HostTask*>::iterator it;
bool bEq = false;
for(it = tss->tasks_.begin(); it != tss->tasks_.end(); it++) { --> //error: invalid use of incomplete type ‘struct TaskScheduler’
if(dynamic_cast<TaskEvent*>(e))
bEq = dynamic_cast<TaskEvent*>(e)->equal(it->second->ev_);
else if(dynamic_cast<HostTask*>(e))
bEq = dynamic_cast<HostTask*>(e)->equal(it->second);
if(bEq) {
return it->second;
}
}
return NULL;
}
//
//class TaskScheduler definition
class TaskScheduler : virtual public HCIEventsHandler {
friend HostTask* findT<TaskEvent>(TaskScheduler* tss, TaskEvent* e); //findT function is used here
//
//
};
Here is the error message that I've got which is shown in the code as well:
./bt-taskscheduler.h:159: error: forward declaration of ‘struct TaskScheduler’
./bt-taskscheduler.h:229: error: invalid use of incomplete type ‘struct TaskScheduler’
Could anybody show me what is going wrong in this code? Any help is appreciated..
In the definition of findT you are using tss->tasks_ which dereferences a pointer to an object of type TaskScheduler so you need a full definition of the struct, not just a forward declaration visible at this point in the program.
The definition of struct TaskScheduler needs to appear before the definition of the findT function template.
You are using the TaskScheduler class in your for-loop header "tss->tasks_.begin()". Compiler does not know, whether this class have "tasks_" member or not.
It is not the problem with your templates, any function, inlined in the header file will cause the same error. Forward declaration of the class only allows you to declare pointers (or references) to that class or pass this class objects as a parameters. You cannot "use" the class (call its methods or get the member data), until you fully define your class.
Because you use the definition of TaskScheduler in the findT functions, you have two options:
Move the definition of TaskScheduler above the findT template function
Make TaskScheduler a second template of of the findT function
Like this:
template< class U, class T>
inline HostTask* findT( U* tss, T* e)
{
//...
}
Next to trouble with the forward declaration, it looks as if your findT function should actually be a member function of the scheduler class: it makes extensive use of the scheduler's data members.
These members are private, so you need a way to publish them, and fall back onto the friend declaration.
So either you make the members public, or, better, you refactor the findT function into a member function.
There's no problem in making it a templated member function, either. And you will automatically get rid of the friend declaration.
//class TaskScheduler definition
class TaskScheduler : virtual public HCIEventsHandler {
public:
template<class T> inline HostTask* findT(T* e) const
{
map<int, HostTask*>::iterator it;
bool bEq = false;
for(it = tasks_.begin(); it != tasks_.end(); it++) {
if(dynamic_cast<TaskEvent*>(e))
bEq = dynamic_cast<TaskEvent*>(e)->equal(it->second->ev_);
else if(dynamic_cast<HostTask*>(e))
bEq = dynamic_cast<HostTask*>(e)->equal(it->second);
if(bEq) {
return it->second;
}
}
return NULL;
}
};
As other posters have mentioned, you are dereferencing a pointer to TaskScheduler without a definition of the type, which will cause an error just as it would in any definition.
What you are probably confused about is that your code likely works on some compilers, even modern ones (I know MSVC is incorrect in this regard, but I do not know if it will accept the above code*). These compilers do not properly implement what is known as two-phase name lookup.
Two-phase name loopkup is a more predictable method of name lookup used in templates than the simpler form used by some compilers. In the simpler form, the template definition is parsed and stored for use only when it's instantiated, and name lookup is performed on all names in the template from the point at which you instantiate the template. With two-phase name lookup, names used within a template are sorted into dependent names and non-dependent names. Non-dependent names are names that the compiler can resolve immediately - any name that doesn't rely on a template parameter, directly or indirectly. These names are processed immediately when you define the template. Dependent names, on the other hand, cannot be resolved immediately; they are stored and then, when instantiation is performed, looked up in the template's context, but also in the context in which the template was instantiated for argument-dependent lookup only.
Here's an example:
void foo (int);
template <typename T> void bar(T t) {
foo(1.0);
foo(t);
}
void foo (double);
struct qux {};
void foo (qux);
void baz () {
bar (1.0);
qux q;
bar (q);
}
N.B. I know I got the metasyntactic names in the wrong order. I apologize, but I added qux last and couldn't be bothered to rewrite my comment.
The instantiations of the bar template each call foo twice. The first call is non-dependent, so the compiler resolves it as soon as it sees it. The result is that it calls foo (int), applying a conversion, even though it will later find a better definition. This is no different from any other function call in C++. The tricky bit comes with the second call, which is dependent. The first call in baz calls bar<double>, the latter calls bar<qux>. The instantiated bar attempts to call foo with an object of type T. In the double scenario, since primitives never use argument-depedent lookup, the result is once again looked up only from bar, and foo(int) is found. When called with qux, however, argument-dependent lookup is applied both in the the definition and instantiation context**, so foo(qux) is called.
It can be a tad stupid, but it tends to Do The Right Thing. Also, I hope you actually understood that; it can be rather confusing. You'll need to read that Wikipedia link to understand fully.
* MSVC may implement a lesser form of two-phase name lookup where it does resolve non-dependent names correctly, but it takes into account definitions after the template for dependent names. I forget whether it does this or omits two-phase lookup entirely and I don't have a copy of the program to check.
** In nearly every case, the instantiation context includes every declaration the definition context does. There is, however, the export keyword which can cause this not to be the case. That keyword is only implemented in one compiler frontend - I wonder why nobody else has implemented it? [/sarcasm]