[英]C++ metaprogramming
我有以下问题:
假设我有一些基本的计数器class Counter
。 并假设我们还有一些可以计数的类集。 让我们将其中一些命名为class CountedA
class CountedB
和class CountedB
。
现在,每个可以计数的类(例如CountedA
和CountedB
)都具有以下静态声明的部分: 一个enum
和一个int
部分,其作用类似于已计数数据的一部分 。
例如,它的声明可能如下所示:
enum CountedType { A, B };
template <CountedType Type, int N>
class Counted { };
// Now we can declare 'CountedA' and 'CountedB'
typedef Counted<A, 25> CountedA;
typedef Counted<B, 7> CountedB;
现在,柜台的声明:
// C++0x variadic or simply bunch of 'typename XX' definitions for C++03
template <typename T0, typename T1, typename ...>
class Counter
{
// I don't know how to implement this
// for now!
int GetTotalN() { ... }
// Retrieve the corresponding type
// so that GetTypeAt<0> returns
// enum from 'T0'
template <int Pos>
CountedType GetTypeAt() { ... }
};
我希望能够编写如下内容:
class RealCounter : public Counter<CountedA, CountedB> { };
并通过以下方式使用它:
RealCounter counter;
int n = counter.GetTotalN();
CountedType type = counter.GetTypeAt<0>();
现在,我很确定可以做到这一点。 但是实现它的最佳方法是什么? (不要问我为什么我需要这么疯狂的事情:)
boost::mpl
在这种情况下是否提供了某些东西?
谢谢。
小更新:
在此特定示例中, GetTotalN()
应该返回25 + 7
。
例如,如果我们添加typedef Counted<C, 2> CountedC
,则结果为
RealCounter : public Counter<CountedA, CountedB, CountedC>
应该变成25 + 7 + 2
。
这是有效的C ++ 03代码(最多10个模板参数)。 主要技巧是为Counter类提供多重继承,并将Counter类型的对象传递给必须选择基类的函数模板。 实际求和是递归完成的。
Counter.hpp
enum CountedType { A, B };
template <CountedType Type, int N>
struct Counted {};
struct DummyCounted {};
template <int Pos, typename T>
struct IndexedType {};
template <unsigned int Terms>
struct PartialSum
{
template <typename CounterT>
static int getSum(const CounterT& ctr)
{ return PartialSum<Terms-1>::getSum(ctr) + ctr.template GetNAt<Terms>(); }
};
template <> struct PartialSum<0U>
{
template <typename CounterT>
static int getSum(const CounterT& ctr)
{ return ctr.template GetNAt<0>(); }
};
template <typename T0, typename T1=DummyCounted,
typename T2=DummyCounted, typename T3=DummyCounted,
typename T4=DummyCounted, typename T5=DummyCounted,
typename T6=DummyCounted, typename T7=DummyCounted,
typename T8=DummyCounted, typename T9=DummyCounted>
class Counter :
public IndexedType<0, T0>, public IndexedType<1, T1>,
public IndexedType<2, T2>, public IndexedType<3, T3>,
public IndexedType<4, T4>, public IndexedType<5, T5>,
public IndexedType<6, T6>, public IndexedType<7, T7>,
public IndexedType<8, T8>, public IndexedType<9, T9>
{
public:
static int GetTotalN() {
return PartialSum<9>().getSum( Counter() );
}
template <int Pos>
static CountedType GetTypeAt() { return _getTypeAt<Pos>( Counter() ); }
template <int Pos>
static int GetNAt() { return _getNAt<Pos>( Counter() ); }
private:
template <int Pos, CountedType Type, int N>
static CountedType _getTypeAt(const IndexedType<Pos, Counted<Type,N> >&)
{ return Type; }
template <int Pos, CountedType Type, int N>
static int _getNAt(const IndexedType<Pos, Counted<Type,N> >&)
{ return N; }
template <int Pos>
static int _getNAt(const IndexedType<Pos, DummyCounted>&)
{ return 0; }
};
Counter.cpp
#include "Counter.hpp"
#include <iostream>
typedef Counted<A, 25> CountedA;
typedef Counted<B, 7> CountedB;
class RealCounter : public Counter<CountedA, CountedB> {};
int main()
{
RealCounter counter;
int n = counter.GetTotalN();
CountedType type = counter.GetTypeAt<0>();
std::cout << "n is " << n
<< "\ntype check is " << (type == A) << std::endl;
return 0;
}
输出:
n is 32
type check is 1
C ++ 0x可变参数模板的内容看起来很有趣,但我尚未对其进行很好的了解。 但是我确实认为在C ++ 0x中,此示例的所有功能(当然main
除外)都可以是constexpr
。
我不确定为什么您需要将这些参数嵌入模板参数中,而不是简单地嵌入到构造函数中,因为对于每个“派生的” CountedA / B类型它们都是相同的类型。
无论如何,您都可以将结果类型嵌入到std :: tuple中,如下面的链接所示(有关示例,请参见Message类)。 然后在下面的链接中创建一个类似于applyTuple版本的可变参数模板函数,该函数将添加所有整数参数,并在所有参数展开后返回最终结果。 至于返回“ Pos”中项目的枚举值,只需调用get(tuple).getEnum()或.value即可获取它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.