I have a template container class that I derive from called MyContainer. MyContainer defines methods like Get(), Set(), etc. to access individual elements. I'd like to make a bitfield class implemented as a MyContainer<char>, where each char element holds CHAR_BIT number of bits. However, to allow the user to operate on individual bits rather than entire bytes, I would have to make Get() and Set() virtual, which is illegal. What are some alternatives?
I was thinking of defining GetBit() and SetBit() in the derived class, but this would violate the Liskov substitution principle. (Think of a SortMyContainer() function.)
EDIT: Here is a simplified example:
template <typename Datatype>
struct MyContainer
{
virtual Datatype Get();
};
template <typename Datatype> // Error: Templates may not be virtual.
virtual Datatype MyContainer<Datatype>::Get() // EDIT: The problem was on this line. The "virtual" keyword should only appear with the function declaration.
{
// ...
}
It is not illegal, only template virtual member functions are.
// valid
template<typename T> class MyContainer {
virtual void set(const T &) = 0;
}
// not valid
class MyContainer {
template <typename T> virtual void set (const T &) = 0;
}
If I got you wrong, please consider placing a code-sample.
edit after your adding of example code:
template <typename Datatype>
virtual // <-- nope, not here
Datatype MyContainer<Datatype>::Get()
{
// ...
}
virtual is only part of the declaration inside the class body. This should be valid:
template <typename Datatype>
Datatype MyContainer<Datatype>::Get()
{
// ...
}
However, note that the definition must be visible at the point of template instantiation. So either put it in the header-file, too (or in an extra-header that you then include into your real header), or leave it in the class-body.
(please nobody mention exported templates now, you and I know them a lot, but they are not quite a beginner topic, and deprecated with the next standard)
You appear to be confused about what constitutes a template. Class templates may have virtual functions, and indeed, those template parameters may appear in those function's signatures.
template<typename T> class an_interface {
virtual T Get() = 0;
};
class a_class : public an_interface<int> {
};
This is perfectly valid. What's not perfectly valid is
class an_interface {
template<typename T> virtual T Get() = 0;
}
Unless the specific member function in question has it's own, separate template parameters, the member function is not a template and may be virtual, irrespective of if it was generated from a class template.
Related
I have an abstract base template class that contains members functions, some that are void, others returning data types ranging from primitive data types to the template parameter data type. I am still new to C++, and I know that I don't necessarily have to implement the pure virtual functions in the base class unless I wish to call them in the derived classes. This idea was fine for member functions that had no return value. For a function that returned an integer, I returned a 0. But when I got to a function that returned a reference to T, the template parameter, I did not know what to do. I tried the two following returns.
template <typename T>
T& AbstractBaseClass<T>::function(){
return T();
}
and
template <typename T>
T& AbstractBaseClass<T>::function(){
return T& tmp= T();
}
But neither seem to work, and I cannot not define these functions because I get an undefined reference error for the functions. I assume this error is because the functions are templates. What is the appropriate way to implement a non-void pure virtual function?
template <typename T>
class AbstractBaseClass{
public:
virtual ~AbstractBaseClass() = 0;
T& function();
}
template <typename T>
T& AbstractBaseClass<T>::function(){
//what must I do here when I don't have any member variable
}
Here is an example of a pure virtual function and a derived class that implements it (some member functions omitted for clarity):
template <class T>
class Base
{
public:
virtual T& get() = 0;
virtual ~Base() = 0;
};
template <class T>
Base<T>::~Base() {}
template <class T>
class Derived: public Base<T>
{
T t;
public:
T& get() override { return t; }
};
Note how get() in Base has no implementation, and the implementation of get in Derived uses a new data member not available in Base.
Note also that a pure virtual destructor, unlike other pure virtual functions, must have an implementation. Normally one doesn't need a pure virtual destructor if there are other pure functions in the class though. It is shown here for illustration.
The title is a mouthful, but basically I wrote something like this:
enum EnumType{ValA, ValB};
template<EnumType> class A {};
template<>
class A<ValA>
{
private:
double param;
public:
A(double param);
};
template<>
A<ValA>::A(double param)
{
// Do Stuff
}
and when I try to compile it I get:
error: template-id 'A<>' for 'A<(EnumType)0u>::A(double)' does not
match any template declaration
Am I doing this wrong?
After searching online for similar cases, I tried to remove template<> (even though I don't understand why this would work), but then I get
multiple definition of 'A<(EnumType)0u>::A(double)'
I guess that I can replace template<> by inline (I tried and it compiles), but that doesn't feel like the proper way to do it (or if it is, I don't understand why).
Can someone explain to me what is wrong with what I wrote, why changing this seems to work, and what's the proper way to do it ?
Can someone explain to me what is wrong with what I wrote, why changing this seems to work, and what's the proper way to do it ?
The standard says:
Members of an explicitly specialized class template are defined in the same manner as members of normal classes, and not using the template<> syntax.
Therefore, in your case you must use:
A<EnumType::ValA>::A(double param)
{
// Do Stuff
}
No template<> at all is just fine. That's because you are actually specializing a (special) member function (the constructor) of an explicitly specialized class template.
See it on coliru.
It would have been different if no explicit specialization was given.
As a minimal working example:
enum EnumType{ValA, ValB};
template<EnumType> class A
{
private:
double param;
public:
A(double param);
};
template<>
A<EnumType::ValA>::A(double)
{
// Do Stuff
}
int main() {
A<EnumType::ValA> a{0.};
}
In this case, template<> is required before the definition of the constructor because you are not defining a specialization of a member function of an already specialized class template.
You missed a semicolon (;) at the the end of class definition.
And the non template member function can be defined this way:
A<ValA>::A(double param) {
// Do Stuff
}
Informally, the template parameter list is only written when necessary, for example, for defining a member function template of a class template, the two template parameter list should all be written
template<class U, class V>
class A{
template <class T>
A();
};
template<class U, class V>
template <class T>
A<U, V>::A() {}
and a empty template parameter list is needed for a explicit specialisation of function template (which, i guess, is the reason why you use so here), informally because it tells the compiler that this is not a function overloading.
EDIT: I didn't actually get a chance to test out any of the suggested solutions as I went on a vacation, and by the time I was back, the people responsible for the class template had made some changes that allowed me to get around the need to use types defined in the class template itself.
Thanks to everyone for their help though.
In a nutshell - and feel free to correct my wording, templates are still a bit of voodoo to me, - I need to know if I can use a (protected) struct or a #typedef defined inside a class template from my specialized class. For example:
This is the class template:
template<typename T>
class A : public C<T>
{
protected:
struct a_struct { /* Class template implementation, doesn't depend on T */ };
void foo( a_struct a );
};
Which I need to fully specialize for T = VAL:
template<>
class A< VAL > : public C< VAL >
{
void foo( a_struct a )
{
// My implementation of foo, different from the class template's
}
};
If I do something like this, however, the compiler complains that a_struct is undefined in my specialized class. I tried specializing and inheriting from the class template but that got... messy.
I saw some solutions, but all of them involved modifying the class template, which is something I am not able to easily do (different team).
Thoughts?
No, you can't use members of the primary template declaration in your specialization of the class template. That is because in essence a template class specialization declares a completely new class template that is applied when the template arguments match the specialization.
You have two options available though, if you want to do something like in your example:
You can specialize the template class member function. This is useful if it is indeed only one member function that is special (or at least the number of member functions is limited).
You can bring the declaration of the member (-type) in a common base class.
Since you indicated in an edit that you can't change the class template itself, specializing the member function seems the best option.
A simplified example of specializing a member function only
template< class T>
class Printer
{
public:
struct Guard {};
void DoPrint( const T& val)
{
Guard g;
(void)g;
std::cout << val << '\n';
}
};
struct Duck {};
template<>
void Printer<Duck>::DoPrint( const Duck& val)
{
Guard g;
(void)g;
std::cout << "Some duck\n";
}
The Guard here is only used to demonstrate that this type is available to both the primary and the specialized implementation of DoPrint().
It's not beautiful, but you can do it like this:
template<typename T>
class C
{
};
template<typename T>
class A : public C<T>
{
protected:
friend A<int>;
// ^^^^^^
struct a_struct { /* Class template implementation, doesn't depend on T */ };
void foo( a_struct a );
};
template<>
class A< int > : public C< int >
{
using a_struct = typename A<void>::a_struct;
// ^^^^^^
void foo( a_struct a )
{
// My implementation of foo, different from the class template's
}
};
or how about, re-declaring struct a_struct in the specialized template, with same functionality as default one.
I know it may not sound good since you need to inject in all specialized templates. But that is one i can think of now.
Say I have a class template in which some methods are type specific.
template <typename T>
class Shape
{
...
void Foo();
...
};
Now I would specialize the type-specific functions using, for example:
void Shape<bool>::Foo() {...};
void Shape<double>::Foo() {...};
Question:
What if Foo should have different parameters depending on the type? Is it possible to specialize a method for a specific type using parameters different from the ones in the class declaration? I suspect it's not allowed, so how should it be done?
How to prevent class instantiation for types for which Foo hasn't been defined?
When should virtual and pure virtual functions should be used in contrast to the siutation I have described? Is it possible to mix both templates and inheritance?
1a . What if Foo should have different parameters depending on the type? Is it possible to specialize a method for a specific type using parameters different from the ones in the class declaration?
No. Yes, As pointed out by Nathan Monteleone below, this is possible by fully specializing the class Shape.
1b . I suspect it's not allowed, so how should it be done?
Can you turn the function itself into a template independent of the class
class Shape {
//...
template <typename T>
void Foo();
//...
};
2 . How to prevent class instantiation for types for which Foo hasn't been defined?
In the class body:
template<typename U> //note the different typename
class Shape {
static_assert(std::is_same<U, bool>::value || std::is_same<U, double>::value, "Type forbidden");
//...
inline void Foo() {
if( std::is_same<U, bool>::value ) Foo_impl_bool();
else if( std::is_same<U, double>::value ) Foo_impl_double();// and so on.
// this function is likely to get optimized since the conditionals are constexpr
}
private:
void Foo_impl_bool();//...
};
3a . When should virtual and pure virtual functions should be used in contrast to the situation I have described?
The answers to 1b and 2 are 2 separate solutions, if neither of them is possible the other possibilities are:
Extract that function into its own class.
Use interface inheritance for this function alone.
3b . Is it possible to mix both templates and inheritance?
Yes
(1) Sort of, but not quite the way you're trying to do it. You basically want the specializations to define the function; it's quite a bit different from when you are declaring base and derived classes.
template <typename T> class Shape {
static_assert(false, "Not implemented");
};
template <> class Shape<bool> {
void Foo(bool a, std::string b) {...}
};
template <> class Shape<int> {
void Foo(int, std::string, whatever else) {...}
};
Even if you were to define Foo in the original non-specialized Shape, it would have no effect on the specializations. Full specializations don't extend the original template, they replace it!
(2) Use static_assert. See the example above.
(3) Yes, you can mix templates and inheritence. Virtual functions runtime polymorphism and static polymorphism. Template parameters have to be known at compile time whereas the exact type of a runtime polymorphic object does not, because they can be referred to by a base class reference. In the templated example above you cannot simply say
template <class T> Shape {...};
...
Shape* myShape; // Compiler error: Shape requires a template parameter
However with inheritence you can:
class ShapeBase { virtual void Foo() = 0; };
class Circle : public ShapeBase { virtual void Foo() { ... } };
class Square : public ShapeBase { virtual void Foo() { ... } };
...
Shape* myShape = new Circle;
myShape->Foo(); // calls Circle->Foo()
Note when you're working with inheritence, the function signatures DO have to match! That's the price you pay for deferring the decision till runtime.
When I want to define a method declared in a template class, but that the method doesn't depend on the template parameters, have I to define it in the include files as :
template class<typename T>
void MyClass::myMethod()
{
...
}
or may I define it in the cpp file as :
void MyClass::myMethod()
{
...
}
?
Thanks.
You'll need to define your method like this:
template class<typename T>
void MyClass<T>::myMethod()
{
// Method Body
}
The reason for this is that the method actually is dependent on the template parameter. Remember that every method has access to the special variable this; during the method call this is actually a parameter passed to the method. this changes in type depending on the template parameter specified during object instantiation and, as such, all methods must be template methods in order to accommodate all forms of this.
Well, if the method doesn't depend on template parameter, you can only do that with inheritance AFAIK.
The downside: more code + inheritance
The upside: (much) less code generated, depending on what parts of your code actually are template dependent. In the below example, method NonDependentMethod will only generate one assembly while DependentMethod will generate as many as there are different template parameters (just one in this case, but make a MyClass<float> and you have two, etc).
#include <iostream>
using namespace std;
class MyClassBase
{
public:
void NonDependentMethod();
};
template <class T> class MyClass : public MyClassBase
{
public:
void DependentMethod(T param);
};
void MyClassBase::NonDependentMethod()
{
cout << "NonDependentMethod" << endl;
}
template<class T> void MyClass<T>::DependentMethod(T param)
{
cout << "DependentMethod " << param << endl;
}
int main() {
// your code goes here
MyClass<int> cls;
cls.NonDependentMethod();
cls.DependentMethod(2);
return 0;
}
Put it in the header file.
The member function is still a member of the class template, and you'd have to write:
template <typename T> void MyClass<T>::myMethod() { /* ... */ }
As with all template member functions, this isn't actually a real function yet; it only generates a real function when the class template is instantiated. So the full template definitions have to be visible to everyone who instantiates the template, and the usual way of doing this is by putting everything in the header.
(Note that member functions of class templates are themselves considered function templates, and you can actually specialize them: template <> void MyClass<int>::myMethod() { }.)
You need to do it this way:
template class<typename T>
void MyClass<T>::myMethod()
{
...
}
It's not the method that is templated, it's the class.
You can have a templated method in a non-templated class, a non-templated method in a templated class (your case) and a templated method in a templated class, and of course a non-templated method in a non-templated class.
You have to define it in an even other way. The method itself may not (directly) depend on the template parameter, but the class to which it belongs certaily does, no? As such, the method indirectly depends on the template parameter too:
template class<typename T>
void MyClass<T>::myMethod()
{ // ^^^ -- note
...
}