You are not logged in.

#1 2009-10-03 15:00:31

ngoonee
Forum Fellow
From: Between Thailand and Singapore
Registered: 2009-03-17
Posts: 7,356

[solved] Template virtual function in C++

I know this isn't legal C++ due to the compiler not being able to determine how big exactly the vtable is. I'm looking for alternatives.

Basically, I have an abstract base class defining the interface for a set of derived classes. One of the functions being exposed through this interface is called run(). Each derived class does something different with run(). So it looks something like this:-

class base {
protected:
  base() { }
public:
  virtual void run(...) = 0;
  /* rest of api here */
};

class derived : public base {
private:
  template<class T>
  void runTemplate() {
    /* Do something with data-type T */
  }
public:
  void run(...) {
    switch(some_int_value_from_the_input) {
      case 1:
        runTemplate<char>();
        break;
      case 2:
        runTemplate<short>();
        break;
      case 3:
        runTemplate<int>();
        break;
      default:
        /* throw error */
    }
  }
};

My 'problem' is that every single derived class has exactly the same run() function, they only differ in the algorithm within runTemplate(). However, since I'm not allowed to implement run() in base calling a templated virtual function in base, I seem forced to have the code above, which seems to me to unnecessarily duplicate code.

Is there another way to implement the above? My objective is to keep the amount of coding done in the derived class to the bare minimum (pretty much just the algorithm if possible), hence why I'm trying to move run()'s definition from derived to base.

Last edited by ngoonee (2009-10-07 14:11:01)


Allan-Volunteer on the (topic being discussed) mailn lists. You never get the people who matters attention on the forums.
jasonwryan-Installing Arch is a measure of your literacy. Maintaining Arch is a measure of your diligence. Contributing to Arch is a measure of your competence.
Griemak-Bleeding edge, not bleeding flat. Edge denotes falls will occur from time to time. Bring your own parachute.

Offline

#2 2009-10-04 07:58:37

ezzetabi
Member
Registered: 2006-08-27
Posts: 947

Re: [solved] Template virtual function in C++

If the run() function is always the same, why is it pure?
What about (done by memory, unchecked):

namespace private_ns {
  template<class T>
  void runTemplate(base*) {
    /* Do something with data-type T */
  }
}

class base {
protected:
  base() { }
public:
  virtual void run(...)  {
    switch(some_int_value_from_the_input) {
      case 1:
        private_ns::runTemplate<char>(this);
        break;
      case 2:
        private_ns::runTemplate<short>(this);
        break;
      case 3:
        private_ns::runTemplate<int>(this);
        break;
      default:
        /* throw error */
    }
  }
  friend template<T> private_ns::runTemplate(...); //done by memory, double check
  /* rest of api here */
};

class derived : public base {
private:
public:
/*I guess you'll put something here*/
};

Last edited by ezzetabi (2009-10-04 08:09:10)

Offline

#3 2009-10-05 10:56:51

ngoonee
Forum Fellow
From: Between Thailand and Singapore
Registered: 2009-03-17
Posts: 7,356

Re: [solved] Template virtual function in C++

Hi ezzetabi, thanks for your help.

I have not actually tried the code above (been away from the office), but from a quick look at it it seems to me that runTemplate cannot be different for different derived classes? Or could it be possible to use the pointer passed to runTemplate to call a templated function in class derived, sort of like:-

namespace private_ns {
  template<class T>
  void runTemplate(base* me) {
    me->mytemplate<T>();
  }
}

class derived : public  base {
public:
  template<class T>
  mytemplate() {
    /* do something depending on T here */
  }
}

Man, just typing that down is making me excited. I'll try it out first thing tomorrow in the office and check back here. But does this work?

EDIT: Now that I think about it... since the input to runTemplate is a pointer to base, it wouldn't be possible to run mytemplate... same limitations as my initial example.

Last edited by ngoonee (2009-10-05 13:43:50)


Allan-Volunteer on the (topic being discussed) mailn lists. You never get the people who matters attention on the forums.
jasonwryan-Installing Arch is a measure of your literacy. Maintaining Arch is a measure of your diligence. Contributing to Arch is a measure of your competence.
Griemak-Bleeding edge, not bleeding flat. Edge denotes falls will occur from time to time. Bring your own parachute.

Offline

#4 2009-10-05 13:48:25

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: [solved] Template virtual function in C++

Template virtual functions are not allowed in C++, no matter what.  The following declaration:

  template<class T>
  virtual void runTemplate() {
    /* Do something with data-type T */
  }

is not valid C++.

Generally you can get around this by templating the class instead of the function, and reworking the logic flow a bit.  However, this means that the run method you've defined above, with a switch on some type, has to be re-thought, because you'll have to instantiate your class based on the type.

class base
{
public:
    virtual void run() = 0;
};

template<class T>
class derived : public base
{
public:
    virtual void run()
    {
         // Do something referencing type T here.
    }
};

Without knowing your specific use-case however I can't offer much more.

Offline

#5 2009-10-05 14:38:54

ngoonee
Forum Fellow
From: Between Thailand and Singapore
Registered: 2009-03-17
Posts: 7,356

Re: [solved] Template virtual function in C++

Hi Cerebral,

I'm familiar with class templatization, but in this case it would not be a good idea for me, as the class itself is going to be used as a dynamic library, so templatizing it would require a rewrite of all my existing code, including that which deals with loading/checking the libraries.

My use-case is actually quite well-specified in the above. Basically, I have a base class which must have a function called run(). Derived classes will each implement their own run() function. However, ALL my derived classes have a runtemplate() function templatized on class, hence ALL of them have an identical run() function (which basically uses switch on an integer to select the specific class being used). As is, this works, but its a bit ugly/uneconomical, not to mention harder to maintain, when I have an exactly duplicated function in every derived class.


Allan-Volunteer on the (topic being discussed) mailn lists. You never get the people who matters attention on the forums.
jasonwryan-Installing Arch is a measure of your literacy. Maintaining Arch is a measure of your diligence. Contributing to Arch is a measure of your competence.
Griemak-Bleeding edge, not bleeding flat. Edge denotes falls will occur from time to time. Bring your own parachute.

Offline

#6 2009-10-05 15:06:50

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: [solved] Template virtual function in C++

Hm.   It's not pretty, but if you wanted to avoid duplicate code, you could use a preprocessor macro:

#define DEFAULT_RUN \
  void run() { \
    switch(some_int_value_from_the_input) { \
      case 1: \
        runTemplate<char>(); \
        break; \
      case 2: \
        runTemplate<short>(); \
        break; \
      case 3: \
        runTemplate<int>(); \
        break; \
      default: \
        /* throw error */ \
    } \
  }

class derived1: public base 
{
private:
    template<class T>
    void runTemplate(...);
public:
    DEFAULT_RUN
};

class derived2: public base 
{
private:
    template<class T>
    void runTemplate(...);
public:
    DEFAULT_RUN
};

Offline

#7 2009-10-05 18:13:50

ezzetabi
Member
Registered: 2006-08-27
Posts: 947

Re: [solved] Template virtual function in C++

Sorry, I do not understand why you cannot use a normal friend function instead of a member function. Ok, you still have a friend declaration, but it should be better than rewriting the function in each derived class.

Offline

#8 2009-10-05 18:31:28

scio
Member
From: Buffalo, NY
Registered: 2008-08-05
Posts: 366

Re: [solved] Template virtual function in C++

ezzetabi wrote:

Sorry, I do not understand why you cannot use a normal friend function instead of a member function. Ok, you still have a friend declaration, but it should be better than rewriting the function in each derived class.

Or polymorphism for that matter.


Edit: Speaking and writing at the same time leads to problems >_< (replace multiple inheritance with polymorphism)

Last edited by scio (2009-10-06 13:42:02)

Offline

#9 2009-10-05 22:30:36

ngoonee
Forum Fellow
From: Between Thailand and Singapore
Registered: 2009-03-17
Posts: 7,356

Re: [solved] Template virtual function in C++

ezzetabi wrote:

Sorry, I do not understand why you cannot use a normal friend function instead of a member function. Ok, you still have a friend declaration, but it should be better than rewriting the function in each derived class.

In the example posted above, the implementation of runtemplate must be supplied in the object file for base. I'm looking for separate implementations of runtemplate in different derived classes. For example (simplified):-

class derived1 : public base {
public
  template<class T>
  runtemplate() {
  T a,b;
  return a+b;
  }
}
class derived2 : public base {
public
  template<class T>
  runtemplate() {
  T a,b;
  return a*b;
  }
}

scio, I'm leery of using multiple inheritance, since my theoretical view of my code is that derived IS A base, and its quite hard to find a base1 and base2 both of which derived has an IS A relationship. That said, I may have (probably) a lack of understanding as to what you're suggesting, could you please be more specific?


Allan-Volunteer on the (topic being discussed) mailn lists. You never get the people who matters attention on the forums.
jasonwryan-Installing Arch is a measure of your literacy. Maintaining Arch is a measure of your diligence. Contributing to Arch is a measure of your competence.
Griemak-Bleeding edge, not bleeding flat. Edge denotes falls will occur from time to time. Bring your own parachute.

Offline

#10 2009-10-05 23:04:15

scio
Member
From: Buffalo, NY
Registered: 2008-08-05
Posts: 366

Re: [solved] Template virtual function in C++

Sorry I typing to you and talking to someone else... I meant polymorphism.
However, I'm not sure if I understand your end goal.  It seems like templates are not needed, but there might be a reason in your code:

class base {
protected:
  base() { }
public:
  virtual void run(...) = 0;
  /* rest of api here */
};

class algowrapper{
public:
  algowrapper(...) {
    /* Use arg to setup algorithm /*
  }
  static void processInput(...) {
    /* Do something with input and defined algorithm */
  }
};

class runner : public base{
protected:
  runner():algo(NULL) { }
  algowrapper* algo;
public:
  virtual void run(...) {
    if (algo)
      algo->processInput();
  }
};

class derived : public runner{
public:
  derived(...):runner(),algo(new algowrapper(/* some algorithm */)) { }
};

class derived2 : public runner{
public:
  derived(...):runner(),algo(new algowrapper(/* different algorithm */)) { }
};

Last edited by scio (2009-10-05 23:05:03)

Offline

#11 2009-10-06 00:22:37

ngoonee
Forum Fellow
From: Between Thailand and Singapore
Registered: 2009-03-17
Posts: 7,356

Re: [solved] Template virtual function in C++

scio wrote:

Sorry I typing to you and talking to someone else... I meant polymorphism.
However, I'm not sure if I understand your end goal.  It seems like templates are not needed, but there might be a reason in your code:

class base {
protected:
  base() { }
public:
  virtual void run(...) = 0;
  /* rest of api here */
};

class algowrapper{
public:
  algowrapper(...) {
    /* Use arg to setup algorithm /*
  }
  static void processInput(...) {
    /* Do something with input and defined algorithm */
  }
};

class runner : public base{
protected:
  runner():algo(NULL) { }
  algowrapper* algo;
public:
  virtual void run(...) {
    if (algo)
      algo->processInput();
  }
};

class derived : public runner{
public:
  derived(...):runner(),algo(new algowrapper(/* some algorithm */)) { }
};

class derived2 : public runner{
public:
  derived(...):runner(),algo(new algowrapper(/* different algorithm */)) { }
};

Hmmm, looks like my explaining skills leave a lot to be desired. Basically I want the separate algorithms to be fully implemented within the derived classes.

Usage case is that, for example, I distribute my executable which includes the object file for base. One of the things my executable does is load .so files (using dlopen), which will be compiled separately from the main executable. These .so files return a pointer to base, but different .so files implement different algorithms. So I can only access the functions which belong to base, since all I have is a pointer to base and no knowledge of the specific derived class, and i just call base->run(...) which is implemented in each derived class and it should handle the rest.

The problem, as I see it, is that runtemplate() shouldn't need to be part of the API in base, yet if it doesn't exist in base, run() cannot call it. Even if it exists in base, it cannot have the form of a template since this is illegal in C++.


Allan-Volunteer on the (topic being discussed) mailn lists. You never get the people who matters attention on the forums.
jasonwryan-Installing Arch is a measure of your literacy. Maintaining Arch is a measure of your diligence. Contributing to Arch is a measure of your competence.
Griemak-Bleeding edge, not bleeding flat. Edge denotes falls will occur from time to time. Bring your own parachute.

Offline

#12 2009-10-06 13:41:01

scio
Member
From: Buffalo, NY
Registered: 2008-08-05
Posts: 366

Re: [solved] Template virtual function in C++

ngoonee wrote:

So I can only access the functions which belong to base, since all I have is a pointer to base and no knowledge of the specific derived class, and i just call base->run(...) which is implemented in each derived class and it should handle the rest.

You just desribed polymorphism.  With my code you could do the following:

base* _base = new derived(...);
_base->run(...); // which runs derived->run(...), which calls algo->processInput(...) doing the specific processing

I guess I'm still stuck on why you need templates for this, it just seems to be causing you more problems than they are worth.
Is something in runTemplate doing template specialization, or template meta-programming?

Offline

#13 2009-10-06 15:45:38

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: [solved] Template virtual function in C++

If you really need templates, you can combine them with Scio's concept too, using template classes instead of template methods:

#include <iostream>
#include <map>
#include <string>

class base
{
protected:
    class algoBase
    {
    public:
        virtual void runAlgo() = 0;
    };
    typedef std::map<int, algoBase*> algoMap;
    algoMap m_algoMap;
public:
    virtual ~base()
    {
        algoMap::iterator it = m_algoMap.begin();
        while (it != m_algoMap.end())
        {
            delete it->second;
        }
        m_algoMap.clear();
    }
    void run(int input)
    {
        algoMap::iterator it = m_algoMap.find(input);
        if (it != m_algoMap.end() && it->second)
        {
            it->second->runAlgo();
        }
    }
};

class derived : public base
{
private:
    template<class T>
    class algorithm : public base::algoBase
    {
    public:
        virtual void runAlgo()
        {
            T a = 31;

            std::cout << a << std::endl;
        };
    };
public:
    derived()
    {
        m_algoMap[0] = new algorithm<int>;
        m_algoMap[1] = new algorithm<char>;
        m_algoMap[2] = new algorithm<bool>;
    }
    virtual ~derived() { }
};

int main()
{
    derived a;
    a.run(0);
    a.run(1);
    a.run(2);
}

Offline

#14 2009-10-06 16:28:39

scio
Member
From: Buffalo, NY
Registered: 2008-08-05
Posts: 366

Re: [solved] Template virtual function in C++

Cerebral wrote:

If you really need templates, you can combine them with Scio's concept too, using template classes instead of template methods

Funny, I was thinking of including something similar in my last post.  In general I try to avoid templated functions and stick to templated classes.

Offline

#15 2009-10-07 06:28:17

the_isz
Member
Registered: 2009-04-14
Posts: 280

Re: [solved] Template virtual function in C++

Just wanted to say: Great solution, Cerebral and scio!

I'd probably given base a mandatory parameter to set up the algorithms
instead of setting them in derived's constrcutor, but that's probably a
matter of taste.

Oh, one last thing: One might consider using boost::function. That way,
you don't even need to define the algo class and can use both functions
and functors from the derived class.

Last edited by the_isz (2009-10-07 06:31:03)

Offline

#16 2009-10-07 11:39:09

Cerebral
Forum Fellow
From: Waterloo, ON, CA
Registered: 2005-04-08
Posts: 3,108
Website

Re: [solved] Template virtual function in C++

the_isz wrote:

I'd probably given base a mandatory parameter to set up the algorithms
instead of setting them in derived's constrcutor, but that's probably a
matter of taste.

Yah, I was going for a quick prototype.  There're definitely style improvements to be made in that regard.

Offline

#17 2009-10-07 13:14:21

scio
Member
From: Buffalo, NY
Registered: 2008-08-05
Posts: 366

Re: [solved] Template virtual function in C++

Cerebral wrote:

Yah, I was going for a quick prototype.  There're definitely style improvements to be made in that regard.

Same here, I didn't test any of mine so it might not even be legal tongue
There's many options here if you start using other libraries, he could even use function pointers if he didn't mind getting into some ugly code smile

Offline

#18 2009-10-07 14:10:42

ngoonee
Forum Fellow
From: Between Thailand and Singapore
Registered: 2009-03-17
Posts: 7,356

Re: [solved] Template virtual function in C++

Thanks all, Cerebral's example looks like it would work. Remains to be seen whether its simpler for the end-user than what I'm currently using, but will have to try that out. Thank you!


Allan-Volunteer on the (topic being discussed) mailn lists. You never get the people who matters attention on the forums.
jasonwryan-Installing Arch is a measure of your literacy. Maintaining Arch is a measure of your diligence. Contributing to Arch is a measure of your competence.
Griemak-Bleeding edge, not bleeding flat. Edge denotes falls will occur from time to time. Bring your own parachute.

Offline

Board footer

Powered by FluxBB