不能在 C++ 构造函数中使用宏?

Cannot use Macro in a C++ constructor?

我有一个复杂的 class,我试图用宏来简化它。该宏适用于某些编译器,但不适用于其他编译器。我以为宏只是文本替换,我错了吗?

struct FooManager
{
    FooManager(){}
    void Add( Foo* i_pFoo ){ m_FooObjects.Add( i_pFoo ); }
private:
    DynamicArray<Foo*> m_FooObjects;
};

struct Foo
{
   Foo( FooManager& mgr, int param1, int param2 = 0 )
       : m_Param1( param1 )
       , m_Param2( param2 )
   {
       mgr.Add( this );
   }
private:
    const int m_Param1, m_Param2;
}

class Bar
{
    FooManager m_Manager;
    Foo m_Foo1, m_Foo2;
public:
    Bar();
};

然后在.cpp文件中...

#define Macro( f, a, ... ) f( m_Manager, a, __VA_ARGS__ )

Bar::Bar()
    : m_Manager()
    , Macro( m_Foo1, 1 )
    , Macro( m_Foo2, 2, 3 )
{}

我在使用 gcc 编译器时得到一个 "error 29: expected an expression"。

我真正想要的是我的 Bar 有一个了解其中所有 Foo 的经理。我可以展开宏,但希望我不必这样做,因为它让事情看起来更清晰,并且它可以根据使用情况提供其他共享参数。

我倾向于认为我这样做违反了一条规则,并且与之一起工作的编译器出于某种原因忽略了这条规则。

__VA_ARGS__ 为空的情况下(例如展开 Macro( m_Foo1, 1 ) 时),您的宏将在构造函数初始化列表中生成以下条目

m_Manager(<some argument>, )

这显然是无效的。 __VA_ARGS__ 的想法是您应该为 __VA_ARGS__ 部分提供至少一个参数。

为了使 __VA_ARGS__ 在这种情况下更易于使用,众所周知,像 MSVC 这样的编译器会在这种情况下实现非标准行为:它们悄悄地删除了过多的逗号,使您的原始代码编译为有意的。

GCC 还实现了一个用于相同目的的非标准扩展,但您必须使用 ##

的非标准技巧来激活它
#define Macro( f, a, ... ) f( m_Manager, a, ##__VA_ARGS__ )

这将在 __VA_ARGS__ 为空时自动删除 GCC 中的尾随逗号。