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.
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
I want to write class that extends multiple classes by (CRTP).
I can only get Extension<Base<Extension>> my_object; to work.
The api that I want is: Extension<Base> my_object;
How to make this api work?
Thanks.
Test (code is also at godbolt.org):
#include <iostream>
template <template<typename...> class Extension>
class Base1 : public Extension<Base1<Extension>> {
public:
static void beep() { std::cout << "Base1 "; }
};
template <class Plugin>
class Extension1 {
public:
Extension1() : plugin_(static_cast<Plugin*>(this)) {}
void beep() {
plugin_->beep();
std::cout << "Extension1\n";
}
private:
Plugin* plugin_;
};
template <template<typename...> class Plugin>
class Extension2 {
public:
Extension2() : plugin_(static_cast<Plugin<Extension2>*>(this)) {}
void beep() {
plugin_->beep();
std::cout << "Extension2\n";
}
private:
Plugin<Extension2>* plugin_;
};
int main() {
// This works.
Extension1<Base1<Extension1>>b;
b.beep();
// This doesn't work.
Extension2<Base1> c;
c.beep();
return 0;
}
One problem is that the template parameter to Extension2 does not match the signature that Base1 has. Another is that Extension2 does not match the parameter type expected by Base1.
If you change the definition of Extension2 to propertly accept Base1, it itself is still not a candidate to be passed to Base1. You can workaround that with an inner template class that does match what Base1 expects. This inner class would look a lot like Extension1.
template <template<template<typename...> class> class Plugin>
class Extension2 {
template <class P>
struct Inner {
Inner () : plugin_(static_cast<P *>(this)) {}
void beep() { plugin_->beep(); }
private:
P* plugin_;
};
public:
Extension2() {}
void beep() {
plugin_.beep();
std::cout << "Extension2\n";
}
private:
Inner<Plugin<Inner>> plugin_;
};
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;
}
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
}
I've two classes:
struct A {
template <typename T>
void print(T& t){
// do sth specific for A
}
};
struct B : A {
template <typename T>
void print(T& t){
// do sth specific for B
}
};
In such case, the more general Base class with virtual functions (which A and B both inherit from) cannot be compiled, since there is no virtual for template. As I try to delegate generally all A or B objects under same "interface", does anyone has the idea to resolve such problem? Thank you in advance.
Sincerely,
Jun
You can think about using using CRTP.
template<typename Derived>
struct Base {
template <typename T>
void print(T& t){
static_cast<Derived*>(this)->print(t);
}
};
struct A : Base<A> {
// template print
};
struct B : Base<B> {
// template print
};
Example Usage:
template<typename T, typename ARG>
void foo (Base<T>* p, ARG &a)
{
p->print(a);
}
This method will be called as,
foo(pA, i); // pA is A*, i is int
foo(pB, d); // pB is B*, d is double
Here is another demo code.
Using a proxy class to get B's method
class A {
public:
friend class CProxyB;
virtual CProxyB* GetCProxyB() = 0;
};
class B;
class CProxyB
{
public:
CProxyB(B* b){mb = b;}
template <typename T>
void printB(T& t)
{
mb->print(t);
}
B* mb;
};
class B:public A {
public:
virtual CProxyB* GetCProxyB(){return new CProxyB(this);};
template <typename T>
void print(T& t){
printf("OK!!!!!\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A* a = new B;
CProxyB* pb = a->GetCProxyB();
int t = 0;
pb->printB(t);
return 0;
}
Two options:
Option one: Virtualize the method where if the user does not provide an implementation, the Base class' is used.
template <typename T>
struct A {
virtual void print(T& t);
};
template <typename T>
void A::print(T& t) {
// do sth specific for A
}
template <typename T>
struct B : A {
virtual void print(T& t);
};
void B::print(T& t) {
// do sth specific for B
}
Option two: Abstract the method where if the user does not provide an implementation, the code will not compile.
template <typename T>
struct A {
virtual void print(T& t)=0;
};
template <typename T>
struct B : A {
virtual void print(T& t){
// do sth specific for B
}
};
template <typename T>
void B::print(T& t){
// do sth specific for B
}
Other than the above mentioned, if you do not make them virtual, the Derived class will Shadow the Base class method and that is most certainly not what you intended. Hence, impossible.
my question is how to use single pointer to different A or B objects.
You can do this without virtual functions per-se. But all you will really be doing is writing an implementation of a V-table and virtual functions.
If I were going to manually implement virtual functions, I would base it all on a Boost.Variant object. The variant would effectively hold the member data for each class. To call a function, you use a variant visitor functor. Each "virtual function" would have its own visitor functor, which would have different overloads of operator() for each of the possible types within the variant.
So you might have this:
typedef boost::variant<StructA, StructB, StructC> VirtualClass;
You could store any one of those objects in the variant. You would call a "virtual function" on the object like this:
VirtualClass someObject(StructA());
boost::apply_visitor(FunctorA(), someObject);
The class FunctorA is your virtual function implementation. It is a visitor, defined like this:
class FunctorA : public boost::static_visitor<>
{
void operator()(StructA &arg){
//Do something for StructA
}
void operator()(StructB &arg){
//Do something for StructB
}
void operator()(StructC &arg){
//Do something for StructC
}
}
Visitors can have return values, which are returned by apply_visitor. They can take arguments, by storing the arguments as members of the visitor class. And so forth.
Best of all, if you ever change your variant type, to add new "derived classes", you will get compiler errors for any functors that don't have overloads for the new types.
But to be honest, you should just be using virtual functions.
By using CRTP(Curiously recurring template pattern), you can achieve static polymorphsim without virtual.
#include <iostream>
using namespace std;
#define MSG(msg) cout << msg << endl;
template<class Derived>
class Base{
public:
void print()
{
static_cast<Derived*>(this)->print();
}
};
class Derived1 : public Base<Derived1>
{
public:
void print()
{
MSG("Derived 1::print");
}
};
class Derived2 : public Base<Derived2>
{
public:
void print()
{
MSG("Derived 2::print");
}
};
template<class T>
void callme(Base<T>& p)
{
p.print();
}
int main()
{
Base<Derived1> p1;
Base<Derived2> p2;
callme(p1);
callme(p2);
system("pause");
return 0;
}
//Result :
//Derived 1::print
//Derived 2::print