1

我正在尝试创建一个宏来生成指向另一个类的实例的指针以表示方向关系。

//#define BIND(A,B) ?
//can be modified a little, top header
BIND(CAT,DOG)
BIND(CAT,TREE)
BIND(CAT,RAT)
BIND(DOG,TREE)
//#define MACRO_CAT (need?) ? 
//#define MACRO_DOG (need?) ?

在此处输入图像描述

上图是相关图。(在实际情况下,有 100 多个类。)
箭头(红色)是Right<>. 箭头尾(绿色)是Left<>。(以下片段)

上面的代码是否有可能像这样自动MACRO_CAT创建宏/ ?:-MACRO_DOG

//v should not be modified
class Cat{
    MACRO_CAT
    /* expand to :-
        Right<Dog> dogs;
        Right<Tree> trees;
        Right<Rat> rats;
    */
};
class Dog{
    MACRO_DOG
    /* expand to :-
        Right<Tree> trees;
        Left<Cat> cats;
    */
};

这种骇人听闻的宏魔法对于维护具有终极性能的对象之间的关系非常有用。

我想X-macro是一个可能的解决方案,但我对此的经验相对较少。
我也读过:-

只是一个粗略的指南/想法表示赞赏。(不需要完整的代码,但我不介意)

编辑:在实际情况下,BIND分散在许多标题中。
这是一个#include流的例子(下#include上):- 在此处输入图像描述

4

1 回答 1

1

在这个解决方案中,我倾向于 TMP 而不是宏。

第一步是收集所有声明的绑定。允许自由声明绑定并将它们分散到其他代码中可能是可行的。但是,它需要某种方式来保持和更新列表的状态,这几乎是您在 C++ 中想要做的最神秘的事情。所以我们不要那样做。

绑定文件必须只包含预处理器指令和对宏的调用BIND,如下所示:

BIND(Cat, Dog)
BIND(Cat, Tree)
BIND(Cat, Rat)
BIND(Dog, Tree)

换句话说,预处理文件必须只包含来自BIND. 然后我们可以将它们夹在bindTop.hand之间bindBottom.h

template <class...>
struct pack;

// Stuff in bindTop.h

#define BIND(T, U) \
    pack<struct T, struct U>,

using AllBindings = pack<

// End of bindTop.h, beginning of the binding file(s)

    BIND(Cat, Dog)
    BIND(Cat, Tree)
    BIND(Cat, Rat)
    BIND(Dog, Tree)

// End of the binding file(s), beginning of bindBottom.h

    void // Pairs up with the last comma,
         // will be silently ignored in further processing
>;

#undef BIND

// Stuff in bindBottom.h

现在我们在里面有了绑定列表AllBindings

下一步:我们如何将成员注入到类中?我已经放弃了宏,而是使用了成员继承。所以类定义如下:

struct Cat  : WithBindings<Cat,  AllBindings> { };

...最终将继承几个结构,这些结构将定义成员Right<Dog> dogs,Right<Tree> treesRight<Rat> rats, 因此几乎可以像访问它们一样访问它们。

但是如何声明Right<Dog>必须调用类型的成员dogs?当然是宏!让我们为左右制作基类制作空模板:

template <class T, class Binding>
struct MakeLeftMember { };

template <class T, class Binding>
struct MakeRightMember { };

然后我们将使用一个宏来为我们的每个类专门化这些,使用类的名称和相应成员的名称:

#define BINDING_MEMBER_NAME(type_, memberName_) \
    template <class T> struct MakeLeftMember<T, pack<type_, T>> { \
        Left<type_> memberName_; \
    }; \
    template <class T> struct MakeRightMember<T, pack<T, type_>> { \
        Right<type_> memberName_; \
    }

Binding预计将是pack<L, R>我们定义的其中之一BIND。现在实例化 eg将仅在isMakeLeftMember<T, pack<L, R>>时分派到特化,也就是说,绑定确实是 T 的左绑定。然后特化将生成适当命名的成员以由 继承。在其他情况下,选择了基本模板,没有任何反应。TRLeft<L>T

最后一个缺失的链接当然是WithBindings<T, AllBindings>,它只是将所有绑定分派给成员制造商并继承生成的成员:

template <class T, class... Bindings>
struct WithBindings<T, pack<Bindings...>>
: MakeLeftMember <T, Bindings>...
, MakeRightMember<T, Bindings>... { };

我们开始了。在 Coliru 上现场观看

于 2017-04-21T19:40:08.707 回答