Is it possible to specialize and define templated static members in some random namespace?

I have a code like this:

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))); 

      

Here ArraySizeHelper calculates the size of the array at compile time. Non-member and non-member functions can be bound. I wrote some macros to save time while writing these bindings:

#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))); \
    }

      

Now you can write above a piece of code like this:

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

      

Much easier to type and read. Why would I put it in a namespace? Because I can't find any other way to write these macros in such a way that the class name only needs to be written once (other than member function pointers) and used with multiple classes. And now I'm wondering if it's okay to do it? If not, is there any other way to implement the functionality I want?

Full code for this example on Pastebin


It turned out to be a bug in GCC 4.7.2 (not sure about other versions)

This code violates 9.4.2 / 2: "The definition for a static data member must appear in the namespace scope enclosing the member class definition."
Here is the bug report: GCC Bugzilla - Bug 56119

+3


source to share


1 answer


Your solution seems to be forbidden by the C ++ 11 standard. Here's what 9.4.2 / 2 says:

"Declaring a static data member in its class definition is not a definition and may be of an incomplete type other than cv-qualified void. The definition for a static data member must appear in the namespace scope enclosing the member class definition. "

Now, the namespace in which you define the static data members (whose name is the result of evaluating the preprocessor expression _Bind##Class##Namespace

) does not contain the namespace in which the class is defined (namely, in your case, the global namespace). So defining a static data member is illegal.

I'm not sure which compiler you are using, but if it compiles this then it is a bug (and indeed it looks like GCC 4.7.2, for example). Clang 3.2 correctly refuses to compile this and prints the correct output message:



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

As for alternative solutions, I don't think there is if you need the class name in the extension BIND_END

(which is what you need for compile-time initialization s_BindingsLength

). If a macro does not receive a class name as an argument, in fact that name should be accessed like typedef

(this would be true if macros were allowed to expand directives #define

, but it is not). Since BIND_END

it has no hint of how to form the class name, it must look for a name that is always the same. And if a name should always be the same, it should be placed in a separate namespace to avoid name conflicts. But this is prohibited by the rule of the above mentioned Standard.

In other words, I am afraid that you need to add one argument to the macro BIND_END

. At the end of the day, it's not too bad.

+2


source







All Articles