我有以下问题:
假设我有一些基本计数器 class Counter
.假设我们还有一些可以计数的类集。让我们将其中一些命名为class CountedA
。和 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 类型的对象传递给必须选择基类的函数模板。实际求和是递归完成的。
计数器.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; }
};
计数器.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
。
关于C++元编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3826608/