gpt4 book ai didi

c++ - 创建宏以将 token (参数)一个一个地收集到列表中

转载 作者:行者123 更新时间:2023-11-30 05:14:24 25 4
gpt4 key购买 nike

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

//#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?) ?

enter image description here

上面是相关图。 (在实际情况下,有 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;
*/
};

这种 hackery 宏魔法对于维持具有最终性能的对象之间的关系非常有用。

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

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

编辑:在实际情况中,BIND分散在许多 header 中。
这是 #include 的示例流量(下#include上):- enter image description here

最佳答案

在此解决方案中,我倾向于使用 TMP 而不是宏。

第一步是收集所有已声明的绑定(bind)。允许自由声明绑定(bind)并将它们分散到其他代码中可能是可行的。然而,它需要一些方法来保持和更新列表的状态,这几乎是 the most arcane thing you would want to do in C++ .所以我们不要那样做。

绑定(bind)文件将必须仅包含预处理器指令,以及对宏BIND 的调用。 ,如下:

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

换句话说,预处理文件必须只包含来自 BIND 的替代输出.然后我们可以将这些夹在 bindTop.h 之间和 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 中有了我们的绑定(bind)列表.

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

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

... 将最终继承自多个结构,这些结构将定义成员 Right<Dog> dogs , Right<Tree> trees , 和 Right<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 定义的.现在实例化例如MakeLeftMember<T, pack<L, R>>只有在 T 时才会 dispatch 到特化是R ,也就是说,绑定(bind)确实是 T 的左绑定(bind)。然后特化将生成适当命名的 Left<L>。成员由 T 继承.在其他情况下,基本模板被选中,没有任何反应。

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

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

我们开始了。 See it live on Coliru !

关于c++ - 创建宏以将 token (参数)一个一个地收集到列表中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43468118/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com