This question is for C++03, not C++11.
I have a case where I am using CRTP with multiple inheritance, and I am curious to know if there is a way to remove the redundancy that is created when specifying the type of B
below.
#include "boost/typeof/typeof.hpp"
#include "boost/units/detail/utility.hpp"
#include <iostream>
#include <string>
struct One{};
struct Two{};
template<typename T>
struct Type
{
static std::string name(void)
{
return boost::units::detail::demangle(typeid(T).name());
}
};
template<typename T1,
typename T2>
struct A
{
typedef A<T1, T2> Self;
A()
{
std::cout << Type<Self>::name() << std::endl;
}
};
template<typename T1,
typename T2,
typename T3>
struct B : public A<One, B<T1, T2, T3> >, // The B<T1, T2, T3> here is redundant
public A<Two, B<T1, T2, T3> >
{
typedef B<T1, T2, T3> Self;
B()
{
std::cout << Type<Self>::name() << std::endl;
}
};
int main(int argc, char* argv[])
{
B<int, int, int> t;
return 0;
}
See this on Coliru
The problem worsens when the number of template parameters for B
increases, when the template arguments themselves are complex, and when B
inherits from A
more times. I'd like to minimize the repetition of B
's template parameters. Specifically, I am looking for a way to access the typedef B<T1, T2, T3> Self
up in the inheritance list for B
, or some equivalent compile-time version of this
.
I cannot:
- Make a typedef for
B
aboveB
using a forward declaration, because I don't have access to the template parameters - Make a typedef inside of the inheritance definition because the syntax doesn't allow that
- Access the typedef from inside the class, because it doesn't exist yet
Something like the below (none of which are not valid code, but display the effect I am looking for):
template<typename T1,
typename T2,
typename T3>
struct B : public A<One, Self>, // Cannot access the typedef yet
public A<Two, Self>
{
typedef B<T1, T2, T3> Self;
};
template<typename T1,
typename T2,
typename T3>
struct B : typedef B<T1, T2, T3> Self, // Invalid syntax
public A<One, Self>,
public A<Two, Self>
{
};
template<typename T1,
typename T2,
typename T3>
struct B : public A<One, B>, // I wish this would work
public A<Two, B>
{
};
template<typename T1,
typename T2,
typename T3>
struct B : public A<One, BOOST_TYPEOF(*this)>, // lol
public A<Two, BOOST_TYPEOF(*this)>
{
};
Is there a way to access a compile-time version of this
?
The problem with:
is that your
template <typename T1, typename T2> struct A
asks to be instantiated withT2
a type, whereas what you wish you could do is instantiate it withT2
a template, namelytemplate<typename, typename,typename> struct B
.If the definition of
A
lies in your own control, then perhaps - though perhaps not - a solution is to make the definition ofA
consistent with your wish:This program prints:
The price of this solution is restricting the classes for which
A
can furnish a CRTP base to ones that instantiate a template, likeB
, of exactly threetypename
parameters.Perhaps you are lucky enough that this restriction does not thwart any other wishes you have. But if you also need
A
to furnish a CRTP base for classes that instantiate some template that does not have exactly threetypename
parameters, then it bites.Provided that all of the classes for which you need
A
to furnish a CRTP base are instantiations of templates that have onlytypename
parameters, and have at mostN
of them, then you can still have a C++03 solution in the same spirit:You define
A
as per the schema:And for each template
Y
for whichA
is to be a CRTP base, you provide exactlyN
parameters, employing "padding" parameters that default tovoid
, as necessary. For example, ifN
== 3:This program prints:
True, the more general solution sticks you with a different kind of "redundancy", in the form of those superfluous defaulted template parameters. But you may find it a less irksome kind.
(gcc 5.1/clang 3.6, C++03)