2

unfortunately my actual template is too full of stuff that is unrelated to my question, so i tried to put everything in a short example. Lets say, I have written the following template:

#include <vector>
template <typename T> class MyTemplate{
  public:
    typedef void(*MyFunc)(T);
    void addFunc(MyFunc f){myFuncs.push_back(f);}
    void callFuncs(T value){
        for (std::size_t i=0;i<myFuncs.size();i++){myFuncs[i](value);}
    }
  private:
    std::vector<MyFunc> myFuncs;
};

I learned already, that I can specialize this template to behave different when the passed type is a vector, so I wrote this:

template <typename T> class MyTemplate<std::vector<T> > {
   public:
       typedef void(*MySingleElementFunc)(T);
       void addSingleElementFunc(MySingleElementFunc f){
           this->mySingleElementFuncs.push_back(f);
       }
       void callFuncs(std::vector<T> value){
           //for (std::size_t i=0;i<myFuncs.size();i++){
           //    myFuncs[i](value);
           //}
           for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
               for (int size_t i=0;i<value.size();i++){
                    mySingleElemetnFuncs[i](value[i]);
               }
           }
       }       
       private:
           std::vector<MySingleElementFunc> mySingleElementFuncs;
};

Now my question is, what is the most elegant way (if possible without inheritance) not only to specialize the template for the case of vector< T > but at the same time still being able to use the first templates methods where vector< T > is the template parameter. What I would like to do later is the following

void Func1(int i){}
void Func2(std::vector<int> i){}

MyTemplate<std::vector<int> > myTemplate;
myTemplate.addFunc(Func1);
myTemplate.addFunc(Func2);

Is it possible to achieve this without simply copy&paste all stuff I need from the original template, to do the same also with the specialized version? I guess I will have to use some kind of inheritance. However, I want to avoid something like this:

MyTemplate<std::vector<int> > myTemplate;
// myTemplate.addFunc(Func1); // does not work
myTemplate.addFunc(Func2);
MyVectorTemplate<std::vector<int> > myVectorTemplate;
myVectorTemplate.addFunc(Func1);   // works  
myVectorTemplate.addFunc(Func2);

i.e. the functionality should be determined only by the type passed to the template but not by choosing the appropriate subclass. Anyhow, I have to admit that I am a bit confused about how to inherit in this case. If it was not a template, I could write something like

class MyVectorClass : public MySingleObjectClass {}

However, the following does not make any sense:

template <typename T> MyTemplate<std::vector<T> > : public MyTemplate<std::vector<T> >

but in some sense, this is what I would like to have.

I am sorry for such a long post and I hope it is more or less clear what is my problem...

EDIT: I just found a mistake in the above code. The loop in the vector template should read

for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
    for (int size_t j=0;j<value.size();j++){
        mySingleElemetnFuncs[i](value[j]);
    }
}

i.e. each registered function should be called once for each entry in the vector. (Otherwise the template does not work if the number of registered functions is not equal to the size of the vector.)

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185

3 Answers3

3

In fact you want add functionality to the specialization, something like:

template <typename T> class MyTemplate<std::vector<T> >
{
public:
   typedef void(*MySingleElementFunc)(T);
   typedef void(*MyVectorFunc)(std::vector<T>);

   void addSingleElementFunc(MyVectorFuncf){
       this->myVcetorFuncs.push_back(f);
   }

   void addSingleElementFunc(MySingleElementFunc f){
       this->mySingleElementFuncs.push_back(f);
   }

   void callFuncs(const std::vector<T>& value){
       for (std::size_t i=0;i<myVectorFuncs.size();i++){
           myVectorFuncs[i](value);
       }
       for (std::size_t i=0;i<mySingleElementFuncs.size();i++){
           for (int size_t i=0;i<value.size();i++){
                mySingleElemetnFuncs[i](value[i]);
           }
       }
   }       
   private:
       std::vector<MySingleElementFunc> mySingleElementFuncs;
       std::vector<MyVectorFunc> myVectorFuncs;
};
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • Actually I was also thinking to do it like this. In my original post you can see that I already started to put some of the code in the vector specialized template (the part that is commented). What I do not like about this solution is that I will have to write duplicate code. Anything that the vector specialization has in common with the non specialized template has to appear again in the specialized version. So... +1 because it solves the problem, -1 because I am not convinced that this is the "most elegant way", and again +1 because "most elegant" is too subjective anyway ;) – 463035818_is_not_an_ai Dec 01 '14 at 10:40
0
template <typename T> 
class MyTemplateBase {
  // generic stuff goes here
};

template <typename T> 
class MyTemplate : public MyTemplateBase<T> {
  // nothing goes here
};

template <typename T> 
class MyTemplate<std::vector<T>> : public MyTemplateBase <std::vector<T>> {
  // specialized stuff goes here
}

If you don't want public inheritance you can use private inheritance, but then you would have to explicitly export everything inherited privately:

template <typename T> 
class MyTemplate<std::vector<T>> : private MyTemplateBase <std::vector<T>> {
 public:
  // generic stuff re-exported
  using MyTemplateBase<std::vector<T>>::Func1;
  using MyTemplateBase<std::vector<T>>::Func2;
  // specialized stuff goes here
}

Might still be worth it, as public inheritance is not exactly the most appropriate tool for code reuse.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • I do not really understand how this solves my problem. Maybe this is also because I was not very clear in stating the question ;). However, in your last code snippet Func1 and Func2 are of same type. – 463035818_is_not_an_ai Dec 01 '14 at 10:35
  • "how this solves my problem". By providing two versions of `MyTemplate`, one extended for vectors, one basic for everything else, without duplicating code. "Func1 and Func2 are of same type". Yes, why does it matter? They are just examples. – n. m. could be an AI Dec 01 '14 at 11:00
  • I tried to implement what I want to do (adding functions and calling them) in the way you proposed. I am having problems with having another method to add a function in the MyTemplate > template. Seems like I cannot add a addFunc( void(*f)(vector < T > )) when there is already a addFunc( void(*f)(T) ). Can you comment on how to deal with that? I really tried, but I could not get a running example with the inheritance scheme you proposed. – 463035818_is_not_an_ai Dec 01 '14 at 12:43
  • If you want to overload inherited `addThis` function, you have to explicitly bring it to scope, like this: `using MyTemplateBase::addFunc;` See e.g. [this](http://stackoverflow.com/questions/14212190/c-issue-with-function-overloading-in-an-inherited-class). – n. m. could be an AI Dec 01 '14 at 13:14
  • Yes, using... made it work :). (even with public inheritance I had to put the "using ...") – 463035818_is_not_an_ai Dec 01 '14 at 13:45
0

I think that, since Vector is a template not a class, should be something like:

template<template <typename ...> class T /*= std::vector*/>
class SomeClass
{
    T x;
};
Exceptyon
  • 1,584
  • 16
  • 23