I have a set of classes that have the following structure:
class U
{
public:
explicit U(int) { ... }
U() {...}
Init(int) {...}
};
I need to be able to compose 1 or more of these classes into a class X. Pseudocode:
template<class TypeSequence>
class X that derives publicly from all the classes in TypeSequence
{
X(int)开发者_如何转开发: all bases are initialized with the integer passed
{}
//if the above constructor is impossible, then the following will do as well:
X(int)
{
Call Init on all bases and pass the given int to them.
}
};
I think I need a lot of mpl, but I'm not really good at it. Is what am I trying to do doable? A code sample would be great.
MY FAULT: Forgot to mention I can't use C++11 features. I am looking for an MPL solution.
Well, Boost.MPL contains metafunctions inherit
and inherit_linearly
you can combine them with for_each
to get the second variant (with init functions). Or using just boost::mpl::fold
and custom metafunctions:
struct Null_IntConstructor
{
Null_IntConstructor(int) { }
};
struct InheritFrom_IntConstructor_Folder
{
template<typename T1, typename T2>
struct apply
{
struct type : T1, T2
{
type(int x) : T1(x), T2(x) { }
};
};
};
template<typename Bases>
struct InheritFrom_IntConstructor
: boost::mpl::fold<Bases,
Null_IntConstructor,
InheritFrom_IntConstructor_Folder>::type
{
InheritFrom_IntConstructor(int x)
: boost::mpl::fold<Bases,
Null_IntConstructor,
InheritFrom_IntConstructor_Folder>::type(x)
{ }
};
Usage example:
#include <iostream>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/vector.hpp>
struct A
{
A(int x) { std::cout << "A::A " << x << std::endl; }
};
struct B
{
B(int x) { std::cout << "B::B " << x << std::endl; }
};
struct C
{
C(int x) { std::cout << "C::C " << x << std::endl; }
};
int main()
{
InheritFrom_IntConstructor< boost::mpl::vector<A, B, C> >(1);
}
Metafunction InheritFrom_IntConstructor
can generalized to accept arbitrary type as constructor parameter and I'm not sure if can generalized to accept arbitrary number of arguments.
Something like this?
template <typename ...BaseClasses>
class Aggregator : public BaseClasses...
{
public:
Aggregator(int i) : BaseClasses(i)...
{}
};
Usage example:
Aggregator<U, V, W> a(10);
Aggregator<U, V> b(15);
Aggregator<W> c(20);
Note: it uses variadic templates, so C++11 is required.
I'm not using Boost, and I'm not sure how much my solution is closer to what you need. But still I'm posting it:
template<typename typeseq>
struct X : typeseq::head, X<typename typeseq::tail>
{
typedef typename typeseq::head base;
typedef X<typename typeseq::tail> recursebase;
X(int i) : base(i), recursebase(i) {}
void init(int i)
{
base::init(i);
recursebase::init(i);
}
};
template<>
struct X<null_type>
{
X(int i) {}
void init(int i) { }
};
And then, testing code:
typedef typelist<S,typelist<U>> typeseq;
X<typeseq> x(10);
x.init(100);
Online demo : http://ideone.com/e6tuM
Something like this should work:
template<class typeOne>
class X1 : public typeOne
{
X(int b): typeOne(b)
{}
};
template<class typeOne, class typeTwo>
class X2 : public typeOne, public typeTwo
{
X(int b): typeOne(b), typeTwo(b)
{}
};
template<class typeOne, class typeTwo, class TypeThree>
class X3 : public typeOne, public typeTwo, public typeThree
{
X(int b): typeOne(b), typeTwo(b), typeThree(b)
{}
};
or, if you're willing to waste a few bytes per object, you can use a placeholder, and only make a large one. This should waste at most one byte per unused base type per instance.
template<int>
class PlaceHolder { PlaceHolder(int){} };
template<
class typeOne,
class typeTwo=PlaceHolder<2>,
class TypeThree=PlaceHolder<3>,
class TypeFour=PlaceHolder<4>,
class TypeFive=PlaceHolder<5>
>
class X :
public typeOne,
public typeTwo,
public typeThree,
public typeFour,
public typeFive
{
X(int b)
: typeOne(b),
typeTwo(b),
typeThree(b),
typeFour(b),
typeFive(b)
{}
X(const X& b)
: typeOne(b),
typeTwo(b),
typeThree(b),
typeFour(b),
typeFive(b)
{}
X& operator=(const X& b) {
typeOne::operator=(b);
typeTwo::operator=(b);
typeThree::operator=(b);
typeFour::operator=(b);
typeFive::operator=(b);}
return *this;
}
};
精彩评论