Combining multiple template classes to one class using typedef

1k views Asked by At

I have the following piece of code. Let us have the function declaration and implementation seperate.

#include <iostream> 

class Y1 {}; 
class Y2 {}; 

template <class T1, class T2> 
class A
{   
    public:
        explicit A();
        void foo() const;
        int bar() const;
};  

template <class T1, class T2> 
A<T1, T2>::A() {}

template <class T1, class T2> 
void A<T1, T2>::foo() const {}

template <class T1, class T2> 
int A<T1, T2>::bar() const {}

int main() {
    A<Y1, Y2> a;
    a.foo();


    A<Y1, Y2> *a2 = new A<Y1, Y2>();
    a2->foo();

    return 0;
}   

It is a pain every time writing

template <class T1, class T2>

for every object declaration and function declaration.

Can someone help with a macro or typedef to shorten the template parameters description.

2

There are 2 answers

0
TheCppZoo On BEST ANSWER

In my own code I also separate the declaration from the implementation. Sometimes I just need the code to know that there exists a template, more often I want to make it very easy to see what the interfaces are.

I have solved this tedious typing with macros. However, the solution is complicated.

In case your return type does not have a comma (that is, excluding cases such as std::unordered_map<int, std::string>) here's a simple utility macro:

#define TEMPLATE2(returnType, className, type1, type2) \
   template<typename type1, typename type2> returnType className<type1, type2>::

You can use it like this:

TEMPLATE2(, A, T1, T2)::A() { ... }

and

TEMPLATE2(int, A, T1, T2)::bar() const { ... }

You could have TEMPLATE1, TEMPLATE3 and so on for more and more template arguments. However, you can also split this into two macros: one that generates the typelist, and one to generate the specialization. I have done them, but believe me, not even I like it. It is not lack of preprocessing skill, I can tell you there is no satisfactory way to avoid the verbiage.

2
R Sahu On

First of all, it will be better to implement the functions in the class definition itself. Then, your problem disappears altogether.

If you must implement the functions outside, you can use something like the macro below for simple return types.:

#define A_FUNC(ret, name) \
template <class T1, class T2> \
ret A<T1, T2>::name

A_FUNC(void, foo)() const {}

A_FUNC(int, bar)()  const { return 0;}

However, for complex return types, that logic will break down. Say you have:

template <class T1, class T2> 
class A
{   
    public:
        explicit A() {}
        void foo() const;
        int bar() const;
        char const* (*)(int, int) bar2() const;
};  

I don't know if there is a way to capture that return type as a macro argument.

Using

A_FUNC((char const* (*)(int, int)), bar2)()  const { return NULL;}

leads to all sorts of compiler errors.