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.
Related
C++ allows to use class and function with the same name in one namespace:
struct S {};
void S() {}
In this case pure name S means function S. To use struct instead you need to explicitly add struct before name.
It's also possible to make function template and still use both of them:
template <class T>
void S() {}
struct S {};
But using template struct is forbidden
void S() {}
template <class T>
struct S {};
and gives error like this:
error: redefinition of 'S' as different kind of symbol
What is the reason for this? Why not to allow use template struct here? Is there any situation where using explicit keyword struct before S (like for non-template version) could not solve name collision if it was allowed? Maybe there is proposal exist?
C++ allows to use class and function with the same name in one namespace.
struct S {};
void S() {}
Normally when you declare struct S, you can refer to the type in two ways: as S and as struct S. But that's only until you declare something else named S, for example, a function. When you do that, the name of the type is not S any more. It's struct S only. The name S is reserved for the function.
This is done for compatibility with C. C code uses this device frequently. Unlike C++, C places struct and union tags in a different name space from normal identifiers, and struct S cannot be referred to as simply S.
So C++, in order to be able to compile C code that uses this device, makes an exception for struct tags that are reused as a different kind of identifier.
As class is nearly synonymous with struct, this is done for the class keyword too.
But C has no templates and there's no need to provide backward compatibility for them, so no such exception for class templates is made.
I think function template name is allowed to be the same as something else to allow overloading, while class template name is explicitly disallowed to match something else according to
14 Templates [temp]
A class template shall not have the same name as any other template, class, function, variable, enumeration, enumerator, namespace, or type in the same scope (3.3), except as specified in (14.5.5).
[update] the rest of this piece makes me think that the case with function template not causing the same error violates the standard requirements:
Except that a function template can be overloaded either by non-template functions (8.3.5) 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.
and VS / clang / gcc seem to disagree on it godbolt
I'm wondering how template member functions work. In particular, when there is an instantiation of the template member function, is the whole class redefined? My confusion comes from the fact that (if I'm right) template classes are not classes in the proper sense. i.e., when instantiated, the compiler creates the definition for a completely new class. The same for template functions. However, classes with a template function seem to be actual classes, so I'm not sure how they could possibly work. Thus, I'm wondering, after instantiating a template member function, what happens with the class definition? Moreover, if I pass a class with a template member function to a template class, can I use the template member function? Could that cause a problem? I tried it once but got an error saying that several functions where defined more that once, although I'm not sure if that was the reason or if there could be an other reason for my error. Is there any further caveat when using static template member functions?
The class definition remains as it is; all the template function does is generate a family of member functions for that class. As an example:
class A {
public:
template<typename T> foo (T &t);
}
Is not conceptually different from you writing:
class A {
public:
foo (bool &t);
foo (int &t);
foo (double &t);
}
...just more convenient. And in the last example, you wouldn't expect a new class to be created for each function would you?
Perhaps the confusion comes from the notion that functions are somehow part of the memory layout of a class; that each function is itself contained in the class, and will be instantiated somewhere in memory whenever an object of the class is created. This notion is incorrect. Functions (templated, global, member, lambda, or otherwise) are never created on the fly or copied around in memory; they are a static and unchanging part of the executable image. The memory layout of the class is not changed by the presence of an extra set of functions, even if those happen to be generated by a template member.
The template class definition is instantiated when you instantiate a class. Each member function of it is instantiated when used. This actually allows you to have member functions that would not work if called when the class is instantiated with some types and not others. However, you must ensure that the signature of the function is either syntactically viable or fails with SFINAE. It will be looked up during the first phase of parsing. The body, if the function isn't itself a template, will be checked for name lookup...so dependent names have to be labeled as such via typename.
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 know that the template class definitions is like:
template <class TYPE>
class cars{
public:
TYPE myCar;
}
but somewhere I encountered to this piece of code:
template <class T>
class polynomialT {
...
}
**************************************
class GFNUM2m {
...
}
**************************************
template class polynomialT<GFNUM2m>;
the last line is vague for me? any one knows what's up? is it an object of polynomialT class?(it seems not because it has no name) is it template?(it seems a duplicate because it has been templated once)
template class polynomialT<GFNUM2m>;
Is a request to explicitly instantiate the template class polynomialT with GFNUM2m, including instantiating all its non-template functions.
Some cases when this is needed are:
When you want to avoid multiple template instantiation (that then get purged by the linker);
When you want to make sure that the full template can be instantiated even for those (non-template) functions not called;
When you want to provide template definitions within a .cpp file;
the last line is equivalent to:
class polynomialT {
protected:
GFNUM2m *coeff; // array of coefficients (? see below)
int degree;
...
}
GFNUM2m *coeff is not an array, is simply a pointer to a GFNUM2m variable. Array and pointer are linked in some way, for example you can allocate dynamically an array with coeff = new GFNUM2m[10], but it is discouraged.
In fact, it is _explicit template instantiation. Use this to get the compiler to generate all (non-nested-template) members of the template class. This is convenient sometimes when linking externally to templated code, to prevent duplication of object code or missing externals (when methods get inlined).
Template specializations seem similar, but require template<> to announce the specialization of an already-declared template. Also, they would define an alternative class definition for that specific template parameter (as #rerun mentions).
Now, on the crosspoint of those, you could see
template<> class polynomialT<GFNUM2m>;
Which IS, in fact, a forward declared template specialization. This would serve to prevent the compiler from auto-instantiating the class template for that type parameter during the rest of the translation unit.
The last line is a forward declaration of the polynomialT class template with a template parameter of GFNUM2m, which also instantiates the template class.
it means template in the class polynomialT is now GFNUM2m class.
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.