简体   繁体   English

C ++元编程

[英]C++ metaprogramming

I have the following problem: 我有以下问题:

Suppose I have some basic counter class Counter . 假设我有一些基本的计数器class Counter And suppose we also have some sets of classes, that can be counted. 并假设我们还有一些可以计数 Let's name some of them class CountedA and class CountedB . 让我们将其中一些命名为class CountedA class CountedBclass CountedB

Now, every class, which can be counted (such as CountedA and CountedB ) has the following statically declared parts: one enum and one int part, that acts like a part of counted data . 现在,每个可以计数的类(例如CountedACountedB都具有以下静态声明的部分: 一个enum和一个int部分,其作用类似于已计数数据的一部分

For example, it's declaration could look the following way: 例如,它的声明可能如下所示:

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;

Now, the declaration of the counter: 现在,柜台的声明:

// 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() { ... }
};

I want to be able to write something like: 我希望能够编写如下内容:

class RealCounter : public Counter<CountedA, CountedB> { };

And use it the following way: 并通过以下方式使用它:

RealCounter counter;
int n = counter.GetTotalN();
CountedType type = counter.GetTypeAt<0>();

Now, I'm pretty sure that this can be done. 现在,我很确定可以做到这一点。 But what's the best way of implementing it? 但是实现它的最佳方法是什么? (don't ask me why would I need such crazy kind of things :) (不要问我为什么我需要这么疯狂的事情:)

Does boost::mpl offer something for this case? boost::mpl在这种情况下是否提供了某些东西?

Thank you. 谢谢。


Small update: 小更新:

In this particular example, GetTotalN() should return 25 + 7 . 在此特定示例中, GetTotalN()应该返回25 + 7

If we add, for example, typedef Counted<C, 2> CountedC , then the result for 例如,如果我们添加typedef Counted<C, 2> CountedC ,则结果为

RealCounter : public Counter<CountedA, CountedB, CountedC>

should become 25 + 7 + 2 . 应该变成25 + 7 + 2

Here's C++03 code which works (for up to 10 template arguments). 这是有效的C ++ 03代码(最多10个模板参数)。 The main trick is giving class Counter a multiple inheritance, and passing objects of type Counter to function templates which must select a base class. 主要技巧是为Counter类提供多重继承,并将Counter类型的对象传递给必须选择基类的函数模板。 The actual summation is done recursively. 实际求和是递归完成的。

Counter.hpp 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 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;
}

Output: 输出:

n is 32
type check is 1

That C++0x variadic template stuff looks interesting, but I haven't taken a good look at it yet. C ++ 0x可变参数模板的内容看起来很有趣,但我尚未对其进行很好的了解。 But I do think in C++0x, all this example's functions (except main of course) could be constexpr . 但是我确实认为在C ++ 0x中,此示例的所有功能(当然main除外)都可以是constexpr

I'm not sure why you need to embed those parameters in the templates arguments and not simply in a constructor since they are all the same types for each "derived" CountedA/B types. 我不确定为什么您需要将这些参数嵌入模板参数中,而不是简单地嵌入到构造函数中,因为对于每个“派生的” CountedA / B类型它们都是相同的类型。

Anyways you can embed the resulting types into a std::tuple as shown in the link below (see Message class for an example). 无论如何,您都可以将结果类型嵌入到std :: tuple中,如下面的链接所示(有关示例,请参见Message类)。 Then create a variadic template function similar to the applyTuple version in the link below that will add all your integer arguments and return the final result once all arguments have been unrolled. 然后在下面的链接中创建一个类似于applyTuple版本的可变参数模板函数,该函数将添加所有整数参数,并在所有参数展开后返回最终结果。 As for the returning of the enum value for the item in "Pos" simply call the get( tuple ).getEnum() or .value to get it. 至于返回“ Pos”中项目的枚举值,只需调用get(tuple).getEnum()或.value即可获取它。

How do I expand a tuple into variadic template function's arguments? 如何将元组扩展为可变参数模板函数的参数?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM