I need to find a way to recursively build a class given a set of template arguments so that the class inherits from itself and build a method f
for the current first template argument in the list of template arguments and then inherits from itself by passing on the rest of the list.
So, basically I want to achieve the following interface for a class C
:
C<T1, T2, T3> c;
c
now has methods C::f(T1)
, C::f(T2)
and C::f(T3)
My approach so far was like this:
// primary template
template <class H, class...>
class C {};
// base case where class... is empty
template <class H, class...>
class C<H>
{
public:
void f(const H& h){
// std::cout << typeid(h).name() << "\n";
}
};
// recursive case where T is nonempty
template <class H, class... T>
class C : public C<T...>
{
public:
void f(const H& h){
// std::cout << typeid(h).name() << "\n";
}
};
This does not actually compile, as I get
error: redefinition of 'C' class C : public C
Is my approach basically possible and just a matter of semantically and or syntactically invalid code or does this approach not work in principle?
For starters, a class cannot inherit from itself.
Secondly, all that you apparently are trying to accomplish is to have each template parameter generate a class method that takes that class as a parameter.
In which case, something like this should work.
Note that this is not a class inheriting from itself. It's a template instance that inherits from another template instance. Each template instance is a unique class.
Note that you have a single definition of the class method in question here, and not two, as you were trying to do. This is a slight improvement.
Another improvement would be to consider rearranging the class hierarchy in this manner, if it's possible to do this taking into consideration your other class requirements:
With this approach, whether you use
C<int, float>
, orC<int, char *>
, the class method will always be declared to be a method ofF<int>
. This cuts down slightly on the resulting code float, since any instance ofC
that includesint
, for example, will generate a single class method instance, instead of two separate methods likeC<int, float>::f(const int &)
andC<int, char *>::f(const int &)
, which would, otherwise, be completely identical.As an alternative approach, I'm proposing a solution based on mixins. Feel free to ignore the boilerplate introduced by class
type_name
, the purpose of which is to show you that the right part is picked up on a per argument base.It follows a minimal, working example:
Some plus of this method:
Part<T>
is defined only once for anyT
, no matter how many times you use it in different packs.S<T, T>
is rejected at compile-time and more in general all those packs that contain the same type two or more times. They would otherwise give births to multiple definitions off(T)
and a subsequent call would be probably ambiguous.You can invoke
f
with a single parameter, as requested. Anyway, as shown in the example, you can invokef
withN
parameters and the call is equivalent toN
calls tof
with a single parameter.In other terms, you can either use this:
Or this:
The result will be the same in both cases.
This feature can be easily turned off if needed by defining
S
as it follows:See it running on wandbox.
As a side note, this is the usual trick used to emulate fold expressions in C++14:
You can find more about that on SO as well as on the web.