I have a base class with a templated function that has the general templated type, as well as specialized version.
#ifndef BASE_CLASS
#define BASE_CLASS
#include <iostream>
using namespace std;
struct Type1
{
};
struct Type2
{
};
class baseClass
{
public:
template<class Type>
void doStuff(Type & t)
{
templateFunction(t);
}
template<class Type>
void templateFunction(Type & t);
};
template<class Type>
void baseClass::templateFunction(Type & t)
{
cout << "This is the generic function!" << endl;
}
template<>
void baseClass::templateFunction(Type1 & t)
{
cout << "This is the specialized function: - Type1" << endl;
}
#endif
I also have a child class, that inherits from "baseClass". However, the child class requires different functionality for that specialization.
#ifndef CHILD_CLASS
#define CHILD_CLASS
#include "BaseClass.h"
class ChildClass : public baseClass
{
public:
};
template<>
void ChildClass::templateFunction(Type1 & t)
{
cout << "We overloaded the specialized template function for type 1!" << endl;
}
#endif
The above does not compile:
ChildClass.h:13: error: no member function âtemplateFunctionâ declared in âChildClassâ
ChildClass.h:13: error: invalid function declaration
If I change the "overloaded" function to:
template<>
void baseClass::templateFunction(Type1 & t)
{
cout << "We overloaded the specialized template function for type 1!" << endl;
}
I get:
ChildClass.h:13: error: redefinition of âvoid baseClass::templateFunction(Type&) [with Type = Type1]â
BaseClass.h:36: error: âvoid baseClass::templateFunction(Type&) [with Type = Type1]â previously declared here
How do I properly overload specialized template functions in child classes?
For reference, the main:
#include "BaseClass.h"
#include "ChildClass.h"
int main()
{
Type1 first;
Type2 second;
baseClass theBaseClass;
ChildClass theChildClass;
theBaseClass.doStuff(first);
theBaseClass.doStuff(second);
theChildClass.doStuff(first);
theChildClass.doStuff(second);
return 0;
}
On the suggestion of: Kerrek SB, I've changed the ChildClass to:
#ifndef CHILD_CLASS
#define CHILD_CLASS
#include "BaseClass.h"
class ChildClass : public baseClass
{
public:
template<class Type>
void templateFunction(Type & t);
};
template<>
void ChildClass::templateFunction(Type1 & t)
{
cout << "We overloaded the specialized template function for type 1!" << endl;
}
#endif
The output:
This is the specialized function: - Type1
This is the generic function!
This is the specialized function: - Type1
This is the generic function!
I was hoping for:
This is the specialized function: - Type1
This is the generic function!
We overloaded the specialized template function for type 1!
This is the generic function!
So this still doesn't work.
The reason why it still doesn't work the way you wanted to is that the function is not virtual in the parent class. However, it is not possible to have a virtual template function.
I see two main options:
as rhalbersma suggested, make the class itself template and then override the desired method s (which now are NOT template) in the child class.
for the specialized method, just write a new method, with a different name, that does whatever you need.
But I'm sure someone will come up with a better idea... =)
You could make a template class with a virtual function like this:
template<typename T>
class B
{
virtual void f() { std::cout << "base template implementation \n"; }
};
template<>
class B<Type1>
{
virtual void f() { std::cout << "base specialized implementation \n"; }
};
template<typename T>
class D: public B<T>
{
virtual void f() { std::cout << "derived template implementation \n"; }
};
template<>
class D<Type1>: public B<Type1>
{
virtual void f() { std::cout << "derived specialized implementation \n"; }
};
B<Type1> b1;
B<Type2> b2;
D<Type1> d1;
D<Type2> d2;
b1.f();
b2.f();
d1.f();
d2.f();
Now there are 2 independent dimensions of customization: either the template T, or the dynamic type (B vs D). For each template instantiation, the virtual functions can be redefined.
More common is to let B be a regular class with pure virtual functions (i.e. an interface), and let D be a template class deriving from B. This lets you redefine the virtual functions of B in a different way for each template instantiation of D (with a suitable default).
Related
Suppose I have a base class as below:
template <typename T>
class Base {
// implementation
void do_something() { /* ... */ } ;
};
then, I create a Derived class as below, and override the do_something() method:
template <typename T>
class Derived : public Base<T> {
// implementation
void do_something() { /* ... */ } ;
};
I know virtualization does not work in class templates, and I am just hiding the implementation of the methods. but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
my question is, given that static_cast of Derived class to base class gives me the do_something of based class, Is there any way that I can store them as base classes while each has their implementation of do_something() class ?
but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
This is already just not possible in C++. In C++, a vector can only contain objects of the same static type. The only way a vector can contain different types of objects is if their static type is still the same, but they have different dynamic types, but this is type erasure/polymorphism which you said you don't want to use.
I think maybe you need to rethink your requirements, because your question in essence reads: I want to do something, but I don't want to use technique X which is explicitly defined as the only way to do that something in C++!
I did this and it seems to work fine:
#include <iostream>
template <typename T>
struct Base {
virtual void do_something() { std::cout << "Base::do_something()\n"; }
};
template <typename T>
struct Derived : public Base<T> {
virtual void do_something() { std::cout << "Derived::do_something()\n"; }
};
int main() {
Base<int> b;
Derived<int> d;
Base<int> *p;
p = &b;
p->do_something();
p = &d;
p->do_something();
return 0;
}
Output:
Base::do_something()
Derived::do_something()
A little variation of the melpomene's answer (adding a no-template base struct, BaseOfBase, for the Base<T> structs) permit the use of a common vector of base of derived classe of different T types.
A working example
#include <vector>
#include <iostream>
struct BaseOfBase
{ virtual void do_something () = 0; };
template <typename T>
struct Base : public BaseOfBase
{
T val;
void do_something ()
{ std::cout << "Base::do_something() [" << val << "]\n"; };
};
template <typename T>
struct Derived : public Base<T>
{ void do_something()
{ std::cout << "Derived::do_something() [" << this->val << "]\n"; } };
int main ()
{
std::vector<BaseOfBase*> vpbb;
Base<int> bi;
Derived<int> di;
Base<std::string> bs;
Derived<std::string> ds;
bi.val = 1;
di.val = 2;
bs.val = "foo";
ds.val = "bar";
vpbb.push_back(&bi);
vpbb.push_back(&di);
vpbb.push_back(&bs);
vpbb.push_back(&ds);
for ( auto const & pbb : vpbb )
pbb->do_something();
}
When we say virtualization doesn't work in template classes, we don't mean that you can't do virtual functions in a template class, nor does it mean that you cannot override a member function with a specialized version of it.
#melpomene showed an example of overriding in general, and I will show here with specialization:
#include <iostream>
template <typename T>
class Base {
public:
virtual T do_something(T in) { std::cout << "Base::do_something()\n"; return in; }
};
class Derived : public Base<int> {
public:
virtual int do_something(int in) { std::cout << "Derived::do_something()\n"; return in - 1; }
};
void main()
{
Base<int> b;
Derived d;
Base<int> *p = &b;
auto r1 = p->do_something(10);
std::cout << r1 <<std::endl;
p = &d;
auto r2 = p->do_something(10);
std::cout << r2 << std::endl;
}
Which will output
Base::do_something()
10
Derived::do_something()
9
Showing that it perfectly works as expected.
What we do mean when saying that
virtualization does not work in class templates
Basically means that you can't use as a template the derived class when the base is expected.
Consider the above classes Base<T> and Derived, then if we have the following code:
#include <memory>
template <typename T>
void Test(std::unique_ptr<Base<T>> in){ std::cout << "This will not work with derived"; }
void main()
{
Base<int> b;
Derived d;
auto ptr = std::unique_ptr<Derived>(&d);
Test(ptr); // <-- Will fail to compile as an invalid argument
}
it will fail because std::unique_ptr<Derived> does not inherit from std::unique_ptr<Base<T>> although Derived itself inherits from Base<T>.
I'm trying to implement compile-time checking of correct implementation of CRTP pattern.
Here is the code:
#include <iostream>
#include <type_traits>
using namespace std;
#define static_interface_check(BaseClass, DerivedClass, FuncName) \
static_assert(!std::is_same<decltype(&DerivedClass::FuncName), decltype(&BaseClass<DerivedClass>::FuncName)>::value, "CRTP error: function " #BaseClass "::" #FuncName " was not overwritten in the class " #DerivedClass);
template <class T>
class Interface
{
public:
Interface();
void foo1()
{
static_cast<T*>(this)->foo1();
}
void foo2()
{
static_cast<T*>(this)->foo2();
}
};
// Checking inside Interface<T> declaration results in incomplete type error, so I had to move it to the default constructor
template <class T>
Interface<T>::Interface()
{
static_interface_check(Interface, T, foo1);
static_interface_check(Interface, T, foo2);
}
class A: public Interface<A>
{
public:
void foo1() { cout << "A::foo1()" << endl; }
};
template <class T>
void bar(Interface<T> &obj)
{
obj.foo1();
obj.foo2();
}
int main()
{
A a;
bar(a);
return 0;
}
It fails during compilation as expected:
error: static assertion failed: CRTP error: function Interface::foo2
was not overwritten in the class T
But I want to use also function overloading, const and non-const versions of the same function.
The question is: how can I implement it for the interface containing void foo(), void foo(int) and void foo(int) const?
How can I check whether my template parameters are derived from a certain base class? So that I am sure that the function Do can be called:
template<typename Ty1> class MyClass
{
...
void MyFunction();
};
template<typename Ty1> void MyClass<Ty1>::MyFunction()
{
Ty1 var;
var.Do();
}
Don't. If the method Do() doesn't exist in the class provided as an argument for Ty1, it will simply not compile.
Templates are a form of duck typing : the abilities of a class are not determined by what interface it inherits from, but by what functionality it actually exposes.
The advantage is that your template can then be used by any class with a suitable Do() method, regardless of where it came from or what bases it has.
You can achieve this using standard type trait is_base_of. Look at the example:
#include <iostream>
#include <type_traits>
using namespace std;
class Base {
public:
void foo () {}
};
class A : public Base {};
class B : public Base {};
class C {};
void exec (false_type) {
cout << "your type is not derived from Base" << endl;
}
void exec (true_type) {
cout << "your type is derived from Base" << endl;
}
template <typename T>
void verify () {
exec (typename is_base_of<Base, T>::type {});
}
int main (int argc, char** argv) {
verify<A> ();
verify<B> ();
verify<C> ();
return 0;
}
And the output is:
your type is derived from Base
your type is derived from Base
your type is not derived from Base
I don't understand why the following code does not compile:
#include <iostream>
using namespace std;
template<typename T>
class Base {
public:
void printTuple(T tuple) {
std::cout << "Hello1!" << std::endl;
}
};
template<typename T>
class Derived : public Base<T> {
public:
void printTuple(std::string name, T tuple) {
std::cout << "Hello2!" << std::endl;
printTuple(tuple);
}
};
int main()
{
Derived<int> d1;
d1.printTuple("Test", 13);
return 0;
}
I get the following error:
main.cpp:19:25: error: no matching function for call to Derived::printTuple(int&)'
But shouldn't Derived inherit a method with such a signature from Base?
Thanks
You should change the line printTuple(tuple) to Base<T>::printTuple(tuple) because a function of the base class has been hidden.
Just add this to the top of the public part of class Derived:
using Base<T>::printTuple;
This will expose the base class overload of the function, i.e. prevent it from being "shadowed."
We would like to specialize member functions of a base class. However, it does not compile. Does anybody know of any alternative that does compile?
Here is an example
struct Base
{
template<typename T>
void Foo()
{
throw "Foo() is not defined for this type";
}
};
struct Derived : public Base
{
template<>
void Foo<int>() { cout << "Foo<int>()" << endl; } // compile error (cannot specialize members from a base class)
template<>
void Foo<double>() { cout << "Foo<double>()" << endl; } // compile error (cannot specialize members from a base class)
};
Eventually, we solved it using overloading.
Here is how the base class looks like
struct Base
{
template<typename T>
class OfType {}
template<typename T>
void Foo(OfType<T>) { static_assert(false, "Foo is not implemented for this type. Please look in the compiler error for more details."); }
};
struct Derived : public Base
{
using Base::Foo;
void Foo(OfType<int>) { // here comes logic for ints }
void Foo(OfType<double>) { // here comes logic for doubles }
};
Here is an example of client code that uses Foo()
template<typename S>
class ClassThatUsesFoo
{
private: S s;
template<typename T>
void Bar(T item)
{
s.Foo(Base::OfType<T>()); // this is the code that uses Foo
DoSomeStuffWithItem(item);
}
};
void main()
{
ClassThatUsesFoo<Derived> baz;
baz.Bar(12); // this will internally use Foo for ints
baz.Bar(12.0); // this will use Foo for doubles
baz.Bar("hello world"); // this will give a verbose compile error
}
This will compile, except for the call to Foo<char>():
#include <iostream>
#include <string>
using namespace std;
struct Base
{
template<typename T>
void Foo()
{
throw "Foo() is not defined for this type";
}
};
struct Derived : public Base
{
template<typename T> void Foo();
};
template<>
void Derived::Foo<int>() { cout << "Foo<int>()" << endl; }
template<>
void Derived::Foo<double>() { cout << "Foo<double>()" << endl; }
int main()
{
Derived derived;
// this is client code
derived.Foo<int>();
derived.Foo<double>();
derived.Foo<char>(); // this throws
}
If you want the call to Foo<char>() -- or any type not specifically specialized by you -- then this works. If you want a non-specialized implementation that works for all types, then you need to add a non-specialized implementation of Foo() as well:
template<typename T>
void Derived::Foo() { cout << "generic" << endl; }
In response to the discussion with Alex (see comments of the answer of John Dibling), this is what I meant (SSCCE):
#include <iostream>
using namespace std;
struct Base
{
template<typename T>
void Foo()
{
//static_assert(false, "Foo() is not defined for this type");
throw "Foo() is not defined for this type";
}
};
// you can add as many specializations in Base as you like
template <>
void Base::Foo<char>() { cout << "Base::Foo<char>()" << endl; }
struct Derived : public Base
{
// just provide a default implementation of Derived::Foo
// that redirects the call to the hidden Base::Foo
template < typename T >
void Foo()
{ Base::Foo<T>(); }
};
// the specializations for Derived
template<>
void Derived::Foo<int>() { cout << "Foo<int>()" << endl; }
template<>
void Derived::Foo<double>() { cout << "Foo<double>()" << endl; }
struct Derived_wo_specialization : public Base
{
/* nothing */
};
int main()
{
Derived d;
d.Foo<char>();
d.Foo<double>();
Derived_wo_specialization dws;
dws.Foo<char>();
dws.Foo<double>();
}