Reputation: 5101
I have the following structure:
class Base {
virtual T foo() = 0;
};
class Derived : public Base {
T foo() override { /**/ }
}
class Derived1 : public Base {
T foo() override { /**/ }
}
I need the following to work (or an adequate substitute):
some_container<unique_ptr<Base>> objects;
Basically,
C++ AMP doesn't allow for virtual functions in kernels, but I definitely need an inheritance chain-like container behaviour.
What is a recommended / common pattern to transform this sort of inheritance chain to template magic?
Upvotes: 2
Views: 179
Reputation: 56863
You could roll your own, manual vtable emulation:
class Base {
protected:
using fp_t = int(*)(Base*);
fp_t fp;
Base( fp_t p ) : fp( p ) {}
public:
int foo() { return (*fp)(this); }
};
class Derived : public Base {
static int sfoo(Base* b) { return static_cast<Derived*>(b)->foo(); }
int foo() { return 42; }
public:
Derived() : Base(&sfoo) {}
};
Upvotes: 0
Reputation: 4450
The canonical method to remove a vtable call is to replace it with a switch statement:
enum type_e
{
type_derived,
type_derived1
};
class Base
{
public:
Base( type_e type ) : m_type( type ) {}
T foo();
private:
type_e m_type;
};
T Base::Foo()
{
switch( m_type )
{
case type_derived:
return //{...} your Derived::Foo()
case type_derived1:
return //{...} your Derived1::Foo()
}
}
The only change in the API is that instead of call new Derived()
you must call new Base( type_derived )
. The major disadvantage is that you now have to hold all of your additional data (formerly members of Derived1 or Derived) in Base
, which may bloat the class. On the other hand you can now make a container of Base by value, and avoid the overhead of std::unique_ptr
.
Upvotes: 1