3

我有一些这样的代码:

template<> const string &Wrapper<Foo>::s_Name = "Foo";
template<> const Binding Wrapper<Foo>::s_Bindings[] = {
    Binding("m1", &caller<&Foo::f1>),
    Binding("m2", &caller<&Foo::f2>),
    Binding("m3", &caller<&Foo::f1>),
    Binding("outer", &caller<&outer>),
};
template<> const int Wrapper<Foo>::s_BindingsLength =
    (sizeof(ArraySizeHelper(s_Bindings))); 

ArraySizeHelper 在这里计算编译时的数组大小。非成员函数和成员函数可以绑定。在编写这些绑定时,我编写了一些宏来节省时间:

#define BIND_START(Class) \
    namespace _Bind##Class##Namespace { \
        typedef Class _BindClass; \
        template<> const string &Wrapper<_BindClass>::s_Name = #Class; \
        template<> const Binding Wrapper<_BindClass>::s_Bindings[] = {

#define BIND(FunctionName, Function) \
            Binding(FunctionName, &caller<Function>),

#define BIND_END \
        };\
        template<> const int Wrapper<_BindClass>::s_BindingsLength = \
            (sizeof(ArraySizeHelper(s_Bindings))); \
    }

现在上面的代码可以这样写:

BIND_START(Foo)
    BIND("m1", &Foo::f1)
    BIND("m2", &Foo::f2)
    BIND("m3", &Foo::f1)
    BIND("outer", &outer)
BIND_END

打字和阅读要容易得多。为什么我需要把它放在命名空间中?因为我找不到另一种方法来编写这些宏,即类名必须只写一次(成员函数指针除外)并将其与多个类一起使用。现在我想知道,这样做可以吗?如果没有,还有其他方法可以实现我想要的功能吗?

此示例在 Pastebin 上的完整代码


这似乎是 GCC 4.7.2 中的一个错误(不确定其他版本)

此代码违反 9.4.2/2:“静态数据成员的定义应出现在包含该成员的类定义的命名空间范围内。”
这是错误报告:GCC Bugzilla – Bug 56119

4

1 回答 1

2

C++11 标准似乎禁止您的解决方案。这就是 9.4.2/2 所说的:

“静态数据成员在其类定义中的声明不是定义,并且可能是除 cv 限定的 void 之外的不完整类型。静态数据成员的定义应出现在包含该成员的类定义的命名空间范围内

现在,您定义静态成员数据的名称空间(其名称是评估_Bind##Class##Namespace预处理器表达式的结果)不包含定义类的名称空间(在您的情况下是全局名称空间)。因此,静态数据成员定义是非法的。

我不确定您使用的是什么编译器,但如果它编译它,那么它就是一个错误(实际上这似乎是 GCC 4.7.2 的情况,例如)。Clang 3.2正确地拒绝编译它并产生正确的输出消息:

source.cpp:106:1: error: cannot define or redeclare 's_Name' here because namespace '_BindFooNamespace' does not enclose namespace 'Wrapper<Foo>' BIND_START(Foo)

至于替代的解决方案,我认为没有,只要你需要在类名中扩展BIND_END(这是你在编译时初始化时需要的s_BindingsLength)。如果宏没有将类名作为参数,实际上,该名称必须作为 a 可用typedef(如果允许宏扩展为#define指令,这是正确的,但它们不是)。由于BIND_END没有提示如何形成类的名称,它必须寻找一个始终相同的名称。如果名称必须始终相同,则必须将其放入单独的命名空间以避免名称冲突。但这是上述标准规则所禁止的。

换句话说,恐怕您必须在宏中添加一个参数。BIND_END毕竟,这还不错。

于 2013-01-26T15:25:41.420 回答