I have a class template that implements a number of functions. I want to be able to also add specialized version of this class which has only a few functions that override those of the base, when a specific type is declared. I know I could achieve this with a class template and explicit specializations of it. However I also want to:
Have the explicit specializations uniquely named, similar to how a base and derived class are uniquely named.
Call the Base functions from an instantiated Derived object, either inside a Derived function, or explicitly as below with obj1.Foo
This is the (simplified) example code I am trying to make work:
In myClasses.h
template<typename T>
class Base
{
public:
void Foo (T& input);
virtual void Bar (T& input);
}
template<>
class Derived : public Base<int>
{
public:
void Bar (int& input) override;
}
In myClasses.cpp
template<typename T>
Base::Foo(T& input) { // Do something generic }
template<typename T>
Base::Bar(T& input) { // Do something generic }
template<>
Derived::Bar(int& input) { // Do something int-dependent }
In main.cpp
int main()
{
Base<int> obj1 = new Derived();
obj1.Foo(input); // Runs Base::Foo
obj1.Bar(input); // Runs Derived::Bar
}
However this code fails with the explicit specialization of non-template Derived error, among others. I've read a lot of StackOverflow threads to get me this far, but I haven't found any that have helped me make this compile. So my questions are:
Is combining class templates with class inheritance possible in this way?
Why does the compiler label the Derived class a non-template despite me explicitly using that keyword?
What is the correct syntax that will make this code work? (assuming what I am trying to do is possible)
EDIT: Following the suggesting of HTNW, I can turn Derived into a regular class by removing the template<> prefix. This will allow everything to compile up to obj1.Foo(input). It seems that the instantiated Derived class can't find or access the base Foo function.
Thanks to ravnsgaard and HTNW for the helpful suggestions which got me to a solution. The key was to remove the template<> keyword from the Derived class (because I wanted it to be a class and not a class template) and declaration of Base<int> at the end of the source file. So the working code looks like this:
In myClasses.h
template<typename T>
class Base
{
public:
void Foo (T& input);
virtual void Bar (T& input);
}
class Derived : public Base<int>
{
public:
void Bar (int& input) override;
}
in myClasses.cpp
template<typename T>
Base::Foo(T& input) { // Do something generic }
template<typename T>
Base::Bar(T& input) { // Do something generic }
Derived::Bar(int& input) { // Do something int-dependent }
template class Base<int>; // VERY IMPORTANT.
In main.cpp
int main()
{
Base<int> &&obj1 = Derived();
obj1.Foo(input); // Runs Base::Foo
obj1.Bar(input); // Runs Derived::Bar
}
In particular, without the template class Base<int>; declaration at the end of myClasses.cpp, the call to obj1.Foo will fail with an error complaining that Derived has no such function.
Related
I have the following code:
template <typename T>
class A {
public:
virtual void func() {
// Things that don't use T parameter.
}
};
class B : public A<int> {
public:
void func() {
A<int>::func();
// Working...
}
};
Basically, I want to override a virtual function defined in a class template from inside a class that inherits from a specialized version of such template (A).
Does this work in C++? Is it good practice? Also, is it ok to call the overridden method as I did in the overriding one? (please, note that, for compatibility with the toolchain I'm using, this is C++98)
Thank you.
Is it possible to declare a templated class in C++ along with the classes it inherits from? Basically I want to give the compiler a hint, that my templated class will always inherit another at declaration time.
Maybe some code will clear up why this is a problem for me:
template<typename T>
class GrandparentClass
{
public:
T grandparentMember;
};
//this needs to be only a declaration, since I do not want classes of ParentClass with random T
template<typename T>
class ParentClass : public GrandparentClass<T>
{
};
// this does not work:
//template<typename T>
//class ParentClass : public GrandparentClass<T>;
// this does not either, because then the child class cannot access the variable from the grandparent class
//template<typename T>
//class ParentClass;
template<>
class ParentClass<int> : public GrandparentClass<int>
{
public:
ParentClass()
{
grandparentMember = 5;
}
};
template <typename T>
class ChildClass : public ParentClass<T>
{
public:
void foo()
{
std::cout << grandparentMember << "\n";
}
};
Also, I cannot use C++ 11.
EDIT:
I found an easy way out of this:
template<typename T>
class ParentClass : public GrandparentClass<T>
{
public:
ParentClass() { ParentClass::CompilerError(); };
};
Just do not define CompilerError() method in the class and everything's fine.
A class declaration is only really useful for non-value variable declarations, like pointers and references. You can't access the class members or even instantiate it, though. Even if you knew that a declared class inherits from some other one, you still wouldn't necessarily be able to utilize that information in any way.
As such, it's only important for the compiler to know what the class inherits from once it learns its full definition.
After clarification in comments: if you want to prevent instantiation of a class template with some types, its definition is the place to do it. A simple static_assert inside the class body will do the trick; Boost.StaticAssert or older SFINAE tricks will do the job for pre-C++11 code.
If you are happy with delaying the error to link-time, rather than compile time, you can declare all the member functions of parent in parent.h, provide definitions in parent.cpp, and explicitly instantiate the finite list of classes that you want.
Parent.h
template<typename T>
class ParentClass : public GrandparentClass<T>
{
ParentClass();
};
class ParentClass<int>;
class ParentClass<long int>; // or whatever
Parent.cpp
template <typename T>
ParentClass::ParentClass() : grandparentMember(5) {}
i have a c++ class like the below one working at vc++ , but doesnt work anymore in linux gcc 4.7. And i have no idea how to make it work again.
test.h
template<typename a>
class test: public a
{
public:
void fun();
};
test.cpp
template<typename a>
void test<a>::fun()
{
template_class_method(); <-- this is a public method from template_class
}
template class test<template_class>;
template_class.h
class template_class {
public:
template_class();
virtual ~template_class();
void template_class_method();
};
template_class.cpp
#include "templateclass.h"
template_class::template_class() {
// TODO Auto-generated constructor stub
}
template_class::~template_class() {
// TODO Auto-generated destructor stub
}
void template_class::template_class_method() {
}
You need to qualify it with the base class name as:
a::template_class_method();
The qualification a:: is necessary because template_class_method exists in a. The C++ rule is that if the base is a class template or template argument, then all its members are not automatically visible to the derived classes. In order to help the compiler to find the member, you need to tell it to look for the member in the base class, for which you need to qualify the member which is of the form of base::member_function() or base::member_data.
In your case, since the base is a, and the member is template_class_method, so you have to write this:
a::template_class_method();
Note that such a base class is called dependent base class since it depends on the template argument.
I don't know why #Karthik T deleted the answer, but that answer was on the right path. You have several options
Use qualified name a::template_class_method()
template<typename a>
class test : public a
{
public:
void fun()
{
a::template_class_method();
}
};
Use class member access syntax this->template_class_method()
template<typename a>
class test : public a
{
public:
void fun()
{
this->template_class_method();
}
};
Make the base class method visible through using-declaration
template<typename a>
class test : public a
{
public:
using a::template_class_method;
void fun()
{
template_class_method();
}
};
Note that the first method will suppress the virtuality of template_class_method (in cases when it is virtual), so it should be used with caution. For this reason, method number 2 is preferred, since it preserves the natural behavior of template_class_method.
Your comment stating that this->template_class_method() "doesn't work" is unclear. It works without any problems. Moreover, as I said above, this is in general case a better option than using a qualified name.
In CRTP to avoid dynamic polymorphism, the following solution is proposed to avoid the overhead of virtual member functions and impose a specific interface:
template <class Derived>
struct base {
void foo() {
static_cast<Derived *>(this)->foo();
};
};
struct my_type : base<my_type> {
void foo() {}; // required to compile. < Don't see why
};
struct your_type : base<your_type> {
void foo() {}; // required to compile. < Don't see why
};
However it seems that the derived class does not require a definition to compile as it inherits one (the code compiles fine without defining a my_type::foo). In fact if a function is provided, the base function will not be called when using the derived class.
So the question is, is the following code replacement acceptable (and standard?):
template <class Derived>
struct base {
void foo() {
// Generate a meaningful error if called
(void)sizeof( Derived::foo_IS_MISSING );
};
};
struct my_type : base<my_type> {
void foo() {}; // required to compile.
};
struct your_type : base<your_type> {
void foo() {}; // required to compile.
};
int main() {
my_type my_obj;
my_obj.foo(); // will fail if foo missing in derived class
}
The whole point of this pattern is, as far as I understand, that you can pass arguments simply as template <typename T> base<T> & and your interface is defined by (non-virtual) functions in base<T>. If you don't have an interface that you want to define (as you are suggesting in the second part of your question), then there's no need for any of this in the first place.
Note that you are not "imposing" an interface like with pure virtual functions, but rather you are providing an interface. Since everything is resolved at compile time, "imposing" isn't such a strong requirement.
In your replacement code you can't "polymorphically" call foo on a base<T>.
However it seems that the derived class does not require a definition to compile as it inherits one (the code compiles fine without defining a my_type::foo).
C++ is lazy : it will not try to make base<my_type>::foo() if you do not actually use it.
But if you try to use it, then it will be created and if that fails, compilation errors will flow.
But in your case, base<my_type>::foo() can be instanciated just fine :
template <class Derived>
struct base {
void foo() {
static_cast<Derived *>(this)->foo();
};
};
struct my_type : base<my_type> {};
void func() {
my_type m;
static_cast<base<my_type>& >(m).foo();
}
will compile just fine. When the compiler is presented with
static_cast(this)->foo(), it will try to find a foo() that is accessible in my_type. And there is one: it's called base<my_type>::foo(), which is public from a publicly inherited class. so base<my_type>::foo() calls base<my_type>::foo(), and you get an infinite recursion.
No, imagine the following situation:
template <typename T>
void bar(base<T> obj) {
obj.foo();
}
base<my_type> my_obj;
bar(my_obj);
Base's foo will be called instead of my_type's...
Do this, and you will get your erro message:
template <class Derived>
struct base {
void foo() {
sizeof(Derived::foo);
static_cast<Derived *>(this)->foo();
};
};
But I must confess I am not sure how this will work in compilers other than GCC, tested only with GCC.
Have a base class A, and a derived class B which overrides function template Func:
class A
{
A() {...};
~A() {};
template <class T>
void Func(const String &sInput, T &tResult)
{...}
};
class B : public A
{
B() {...}
~B() {};
template <class T>
void Func(const String &sInput, T &tResult)
{...}
};
(Note that Func is non-virtual, given the lack of support in C++ for templated virtual functions.)
Now have a mainprog API, class M:
class M
{
M(boost::shared_ptr<A> &pInterfaceInput): pInterface(pInterfaceInput)
{}
template <class T>
Evaluate(const String &sInput, T &tResult)
{
pInterface->Func<T>(sInput, tResult);
}
private:
const boost::shared_ptr<A> pInterface;
};
I want the function Evaluate here to support calls to functions on base class A or any of its derived classes (such as B). This class was written with polymorphism in mind before I re-designed class A and B to have templated functions.
Now the problem here is that if I pass a shared pointer of the base type to the derived type then Func of the base class will be called, not the derived class being pointed to.
How do I get around the lack of dynamic polymorphism here?
I've considered making class M a class template on the shared pointer type and having a static_cast in the constructor to ensure this type is of the base class type (A) or of a derived class.
What's the nicest way to do this? I'd prefer not to modify classes A and B to get around this problem but all suggestions are welcome.
Thanks.
Sounds like a double dispatch problem. Perhaps this would be a good place to implement the visitor pattern?
For example, create a class Evaluator, and for each T a subclass ConcreteEvaluator<T>. Give A and B methods that visit the Evaluator. Something like:
class Evaluator
{
virtual void visit_A(A* object);
virtual void visit_B(B* object);
};
template <typename T>
class ConcreteEvaluator : public Evaluator
{
public:
String* input_reference;
T& result_reference;
ConcreteEvaluator(String& input_reference_,T& result_reference_) :
input_reference(input_reference_),
result_reference(result_reference_) {}
virtual void visit_A(A* object) {
object->Func(input_reference,result_reference);
}
virtual void visit_B(B* object) {
object->Func(input_reference,result_reference);
}
}
class A
{
...
virtual void apply_evaluator(Evaluator *eval) {eval->visit_A(this);}
...
}
class B
{
...
virtual void apply_evaluator(Evaluator *eval) {eval->visit_B(this);}
...
}
For each subclass of A, a new method must be added to ConcreteEvaluator, so that this technique works best if A's class hierarchy is stable. And for each subclass of A, it must have an apply_evaluator function defined properly.
On the other hand, this may be total overkill. For about the same amount of work, you could always just pay the price to update M::Evaluate:
class M
{
...
void Evaluate(const String& sInput, T& tResult)
{
// try to downcast to each subclass of A. Be sure to check
// sub-subclasses first
try
{
dynamic_cast<B*>(pInterface.get())->Func(sInput, tResult);
return;
}
catch (std::bad_cast& ) { }
...
// nothing worked. It must really be an A
pInterface->Func(sInput,tResult);
}
...
};
I've show in the question Templatized Virtual function how to use type erasure to get some of the effects of virtual member function. Depending on what you want to do in Func(), you can use the same technique here.