tags:

views:

130

answers:

1

Hey!

I'd like to create a template interface for data-handling classes in my projects.

I can write something like this:

template <class T>
class DataHandler
{
    public:
        void Process(const& T) = 0;
};

Then, suppose, I define a class this way:

class MyClass: public DataHandler<int> 
{
    void Process(const int&) { /* Bla-bla */ }
}

Now, come the question, can I somehow define my template interface in the way that as parameter it will recieve not just type T, but the whole signature of the Process() function.

I would like something working this way:

class MyClass: public DataHandler<void (int&)> 
{
    void Process(const int&) { /* Bla-bla */ }
}

Is it possible? I know that, for instance, boost::signal receives template parameters this way, but, if I understand correctly, they use lot of black-magic there.

+7  A: 

Yep you can. But in C++03, you are bound to do copy/paste code for every number of parameters (not too bad, since here you won't need overloads for const/non-const etc. The constnes is already known!).

template<typename FnType>
struct parm;

template<typename R, typename P1>
struct parm<R(P1)> {
  typedef R ret_type;
  typedef P1 parm1_type;
};

template <class T>
class DataHandler
{
    typedef typename parm<T>::ret_type ret_type;
    typedef typename parm<T>::parm1_type parm1_type;

    public:
        virtual ret_type Process(parm1_type t) = 0;
};

class MyClass: public DataHandler<void (const int&)> 
{
    void Process(const int&) { /* Bla-bla */ }
};

In C++0x, you will be able to write

template <class T>
class DataHandler;

template<typename R, typename ... P>
class DataHandler<R(P...)> 
{
    public:
        virtual R Process(P... t) = 0;
};

class MyClass: public DataHandler<void (const int&)> 
{
    void Process(const int&) { /* Bla-bla */ }
};

How much nicer!

Johannes Schaub - litb
Now the question remains: how many years will it take until we can put variadic templates to daily use at work. Knowing how much simpler it could be can hurt...
Georg Fritzsche
Lev
@Lev, I suspect you will have to partially specialize `DataHandler` on the function type so you get the `Process` function declaration right too. `boost::function` uses the preprocessor to generate the code needed, but for own projects and a few uses, it's hardly useful (in my opinion) to introduce yourself into that topic you are likely you don't need anymore afterwards. So just copy/paste 4 times and be done :)
Johannes Schaub - litb
Johannes, could you please explain what is the meaning of the pre-declaration of struct parm you did as the first lines of your answer?
Lev
@Lev, it's not defined. So if we do `parm<int>::parm1_type` we get an error about that we should define `parm<int>`. I could have added braces like `{};` to define the template, and then it would say that there is no type "parm1_type". Leaving it undefined signals to readers of the code that we do not intend to have any meaning for that case.
Johannes Schaub - litb