I have the following code that doesn't compile.
class Base {
public:
virtual ~Base() { };
};
class Derived : public Base { };
class NotDerived { };
template <typename T>
class Group { };
int main() {
Group<Base> *g = NULL;
g = new Group<Base>(); // Works
g = new Group<Derived>(); // Error, but I want it to work
g = new Group<NotDerived>(); // Error, as expected
}
I understand that this won't compile because g is a different type than Group<Derived>. To make this work in Java I would do something such as Group<? extends Base> g, but C++ doesn't have that keyword as far as I know. What can be done?
Edit: I would like to clarify that I do not want it possible to set types not derived from Base as g. I have updated my example to explain this.
Edit 2: There are two solutions to my problem. Dave's I found to be simple and easy to define. But Bowie's (along with Mark's additions) suited my needs better.
The classes Group<Base> and Group<Derived> are entirely unrelated, different classes. Pointers to them are not convertible in either direction.
If you need runtime-polymorphic behaviour, your class template Group could derive from a common (non-templated) base class:
class Group // base
{
virtual ~Group() { }
};
template <typename T>
class ConcreteGroup : public Group
{
// ...
T * m_impl;
};
Group * g1 = new ConcreteGroup<A>;
Group * g1 = new ConcreteGroup<B>;
You could make Group< Base > a base class of all Group< T > T != Base.
class Base {
public:
virtual ~Base() { };
};
class Derived : public Base { };
template <typename T> class Group;
struct Empty { };
template <typename T>
struct base_for_group_t {
typedef Group<Base> type;
};
template <>
struct base_for_group_t<Base> {
typedef Empty type;
};
template <typename T>
class Group : public base_for_group_t<T>::type { };
int main() {
Group<Base> *g = 0;
g = new Group<Base>(); // Works
g = new Group<Derived>(); // now works
}
Bowie Owens's Answer handles the covariance you need to solve the original question. As for the constraint you asked for in the edited question - you can achieve this by using type traits.
template <typename T, class Enable = void> class Group;
template <typename T>
class Group<T, typename enable_if<is_base_of<Base, T>::value>::type>
: public base_for_group_t<T>::type { };
I don't think C++ support that. C++ Template is handled completely at compile time so it doesn't support polymorphism. That means the type of the template arguments should be exactly the same for both side of the assignment expression.
I think I understand what you're going for. I'm not sure it's the best approach (and you might want to look at Boost.Factory).
template <class T>
class Factory {
public:
virtual T* operator()() = 0;
};
template <class Derived, class Base>
class ConcreteFactory : public Factory<Base> {
public:
virtual Base* operator()() {
return new Derived();
}
};
class Base {
public:
virtual ~Base() {};
};
class Derived1 : public Base { };
class Derived2: public Base {};
class NotDerived {};
int main()
{
Factory<Base>* g;
g = new ConcreteFactory<Derived1, Base>;
g = new ConcreteFactory<Derived2, Base>;
// g = new ConcreteFactory<NotDerived, Base>; // Will not work if you try to do this
}
Related
I have a class that receives its base type as a template arg and I want my derived class to call a function, print. This function should use the derived implementation by default but if the base class has a print function it should use the base implementation.
#include <iostream>
class BaseWithPrint {
public:
static void print(int i) { std::cout << "Base::print\n"; }
};
class BaseWithoutPrint {
};
template <typename B>
class Derived : public B {
public:
static void print(bool b) { std::cout << "Derived::bool_print\n"; }
template <typename T>
static void print(T t) { std::cout << "Derived::print\n"; }
void Foo() {
print(1);
print(true);
print("foo");
}
};
int main()
{
Derived<BaseWithPrint> d1;
d1.Foo();
Derived<BaseWithoutPrint> d2;
d2.Foo();
return 0;
}
This code only ever calls the Derived version of print.
Code can be seen at
https://onlinegdb.com/N2IKgp0FY
If you know that the base class will have some kind of print, then you can add using B::print to your derived class. If a perfect match isn't found in the derived, then it'll check the base.
Demo
To handle it for the case where there may be a base print, I think you need to resort to SFINAE. The best SFINAE approach is really going to depend on your real world situation. Here's how I solved your example problem:
template <class T, class = void>
struct if_no_print_add_an_unusable_one : T {
// only ever called if derived calls with no args and neither
// the derived class nor the parent classes had that print.
// ie. Maybe best to force a compile fail:
void print();
};
template <class T>
struct if_no_print_add_an_unusable_one <T, decltype(T().print(int()))> : T {};
//====================================================================
template <class B>
class Derived : public if_no_print_add_an_unusable_one<B> {
using Parent = if_no_print_add_an_unusable_one<B>;
using Parent::print;
public:
// ... same as before
};
Demo
The following is the simplified code to show my idea.
#include <iostream>
struct base {
virtual int test(){return 0;}
};
struct derived : public base {
virtual int test(){return 1;}
};
template <typename T>
struct foo : public T {
virtual int bar() { return 2;}
};
typedef foo<base> foo_base;
typedef foo<derived> foo_derived;
int main(int argc, char ** argv) {
base * p = new derived(); //It is OK.
std::cout<<p->test()<<std::endl;
foo_base * foo_p = new foo_derived(); //It is not OK
std::cout<<foo_p->bar()<<std::endl;
foo_base * foo_p2 =(foo_base *)(new foo_derived()); //It is working
std::cout<<foo_p2->bar()<<std::endl;
delete foo_p2;
delete foo_p;
delete p;
return 0;
}
I know it is not OK due to the template changing the class inheritance. Is there an elegant way to make the inheritance keep the same after applying the template ?
More specifically, is it possible to build an inheritance between foo<base> and foo<derived>, for example, by using some proxy templates or special pattern like CRTP to rebuild same inheritance after the template instantiation?
As said by Sam Varshavchik in the comments, you cannot automate this process completely since C++ does not have reflection, and thus can't list base classes. However, you've already gone down the route of typedefing your template instantiations, and this is the perfect place to list base classes yourself (hanges highlighted in comments):
struct base {
// Don't forget the virtual destructor for polymorphic destruction
virtual ~base() = default;
virtual int test() const { return 0; }
};
struct derived : base {
int test() const override { return 1; }
};
// U... is the list of thebase classes for T
template <typename T, typename... U>
struct foo : T, foo<U>... {
// ^^^^^^^^^^^ Inheritance is mirrored here
virtual int bar() const { return 2; }
};
// base has no base class
typedef foo<base> foo_base;
// derived has one base class, base.
typedef foo<derived, base> foo_derived;
Live example on Coliru
For this particular project, I am not able to use C++11 features (e.g. decltype) because the compiler does not yet support them. I need to be able to provide the current class as a template parameter, preferably within a macro without an argument (see below), without dressing up the class declaration or hiding curly braces, etc.
class Foo: private Bar<Foo> {
MAGIC //expands to using Bar<Foo>::Baz; and some others
public:
void otherFunction();
//... the rest of the class
};
Ideally, I'd like this to work very much like Qt's Q_OBJECT macro, but without introducing another pre-compile step and associated generated classes. typeid might be useful at runtime, but my goal is to accomplish all of this at build.
How do I write the MAGIC macro so that I don't need to repeat the class name each time?
What about:
template<typename T>
class Base
{
protected:
typedef Base<T> MagicBaseType;
namespace Baz { }
};
class Derived1 : private Base<Derived1>
{
using MagicBaseType::Baz;
}
class Derived1 : private Base<Derived2>
{
using MagicBaseType::Baz;
}
or, if you can't modify the Base definition, using templates and multiple inheritance
template<typename T>
class Base
{
protected:
namespace Baz { }
};
template<typename T>
class DerivedTemplate : public T
{
protected:
typedef typename T BaseType;
}
class Derived : public Base<Derived>, public DerivedTemplate<Base<Derived>>
{
using BaseType::Baz;
}
I don't think there is any language supported mechanism to extract the base type from a class. You can use:
Option 1
class Foo: private Bar<Foo> {
#define BASE_TYPE Bar<Foo>
// Use BASE_TYPE in MAGIC
MAGIC //expands to using Bar<Foo>::Baz; and some others
#undef BASE_TYPE
public:
void otherFunction();
//... the rest of the class
};
Option 2
class Foo: private Bar<Foo> {
typedef Bar<Foo> BASE_TYPE;
// Use BASE_TYPE in MAGIC
MAGIC //expands to using Bar<Foo>::Baz; and some others
public:
void otherFunction();
//... the rest of the class
};
If you really don't care about formatting or writing a maintenance headache you can do this without repeating the type by having the macro take the type argument:
#define MAGIC(BASE) \
BASE { \
using BASE::baz;
class Sub : private MAGIC(Base<Foo>)
public:
void otherFunction();
};
but this makes me feel pretty bad about myself
You could use a "proxy"(?) struct for Building up the inheritance:
template <typename S>
struct Base : public S{ //always public, access is restricted by inheriting Base properly
using super = S;
};
Usage would be as follows:
#include <iostream>
template <typename S>
struct Base : public S {
using super = S;
};
template <typename T>
class Bar
{
public:
virtual void f() { std::cout << "Bar" << std::endl; }
};
class Foo : private Base<Bar<int>>
{
public:
virtual void f()
{
std::cout << "Foo";
super::f(); //Calls Bar<int>::f()
}
};
class Fii : private Base<Foo>
{
public:
virtual void f()
{
std::cout << "Fii";
super::f(); //Calls Foo::f()
}
};
int main()
{
Fii fii;
fii.f(); //Print "FiiFooBar"
return 0;
}
What I want to doe is a simple conditional inheritance in the Foo class
so depending on how it's instanciated (see usage)
class BaseType
{
protected:
m_valueX;
public: BaseType(int param = 0):m_valueX(param){}
~ BaseType(){}
}
...
class Type1 : public BaseType
{
public: Type1():BaseType(1){}
~Type1(){}
}
...
class Type2 : public BaseType
{
public: Type2(): BaseType(2){}
~Type1(){}
}
...
template<typename Base>
class Foo: public Base
{
public:
Foo(){}
~Foo();
void dothis();
}
...........
in cpp file
template<typname Base>
Foo<Base>::Foo():Base()
{
}
Foo::~Foo(){}
void Foo::dothis(){}
usage:
Foo* fooptr1 = new Foo<Type1>();<== error use of class template requires template argument list
Foo* fooptr2 = new Foo<Type2>();>();<== error use of class template requires template argument list
Thank you!
Foo is a template, not a class. The common class type for all Foo<T> is Base, so you can say:
Base * p1 = new Foo<Type1>;
Base * p2 = new Foo<Type2>;
This question relates very closely to Can a nested C++ class inherit its enclosing class?
My situation is complicated with templates which seemingly mean that the previous answer no longer works.
class Animal
{
template <typename T>
class Bear : public Animal
{
// …
};
template <typename T>
class Giraffe : public Animal
{
// …
};
};
// example usage
struct MyAnimal : Animal::Bear<Animal> { };
MyAnimal a;
Can something like this be made to work?
The other answer works, you just need to know the syntax for it:
class Animal
{
template <typename T>
class Bear;
template <typename T>
class Giraffe;
};
template <typename T>
class Animal::Bear : public Animal
{
....
};
template <typename T>
class Animal::Giraffe : public Animal
{
....
};
Sure it can. Like suggested in the original question just use forward declaration.
#include <iostream>
class Animal
{
public:
template <typename T>
class Bear;
template <typename T>
class Giraffe;
int val;
};
template <typename T>
class Animal::Bear : public Animal
{
public:
T b_member;
virtual void print(){
std::cout << b_member.val << endl;
}
};
template <typename T>
class Animal::Giraffe : public Animal
{
public:
T g_member;
virtual void print(){
std::cout << g_member.val << endl;
}
};
struct BearAnimal : Animal::Bear<Animal>
{
};
struct GiraffeAnimal : Animal::Giraffe <Animal>
{
};
int main()
{
BearAnimal btest;
GiraffeAnimal gtest;
btest.b_member.val = 1;
gtest.g_member.val = 2;
btest.print();
gtest.print();
return 0;
}
Output:
1
2
You can't do that because inheriting requires the full class definition to be available. Since Bear and Giraffe's use within Animal could affect the definition of Animal you wind up almost with a circular dependency.
Instead, group the related classes in a namespace. I see no reasons why specific animals should be nested within Animal at all.