2

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?

ScarletAmaranth
  • 5,065
  • 2
  • 23
  • 34
  • Take a look at `boost::variant`. That might be helpful in order to have a common list of different types. – Shoe Oct 25 '13 at 23:36
  • Relevant http://stackoverflow.com/questions/18859699/c-generating-an-interface-without-virtual-functions/18859931#18859931 Let me know if you think it's a dupe! (And hi! Gauntlet still there?) – sehe Oct 25 '13 at 23:42
  • Gauntlet still on the ground, just a tad busy with life :). The linked thing has some useful ideas, I'll take a closer look. – ScarletAmaranth Oct 25 '13 at 23:45
  • @sehe Oh ye, the boost::variant will likely do, thanks. – ScarletAmaranth Oct 25 '13 at 23:52
  • 2
    Or this somewhat [similar discussion/example in the lounge](http://chat.stackoverflow.com/transcript/message/12376009#12376009) (also links to the all important Sean Parent talk ["Inheritance Is The Base Class of Evil"](http://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil)) – sehe Oct 25 '13 at 23:54

2 Answers2

1

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.

Dan O
  • 4,323
  • 5
  • 29
  • 44
0

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) {}
};

Live example

Daniel Frey
  • 55,810
  • 13
  • 122
  • 180
  • Yeah, that looks like sane. I actually don't know what the problem with CUDA is; as it stands, you'll still need to have dynamic allocation in the device memory, which I imagine to be the hard part. – Kerrek SB Oct 26 '13 at 00:07
  • @KerrekSB It looks like there is a problem with functional calls in general on the GPU as there is no notion of stack. It seems that everything is strictly inlined and de-virtualizing calls, whenever not impossible, is difficult. – ScarletAmaranth Oct 26 '13 at 13:25