How to specialize a class template in a different namespace than thecurrent one?

P

Patrik Kahari

A common pattern is to have users register their classes with a
framework. By having users specialize a templated class, located in
the framework namespace, with their user types. To make this easier
for users a macro function is often used. The problem becomes that
users can not use this macro from within any user namespaces. This
makes the macro less useful. Is there a way around this?

<CODE>

namespace LibNs1 {
namespace LibNs2 {
template<typename T>
struct RegsiterClass {};
}
}

//Works but expects to be called from root namespace which is
cumbersome for users
#define REGISTER_CLASS_WITH_LIB_V1(T) \
namespace LibNs1 { \
namespace LibNs2 { \
template<> \
struct RegsiterClass< T > {}; \
}} \

//does not work
#define REGISTER_CLASS_WITH_LIB_V2(T) \
template<> \
struct ::LibNs1::LibNs2::RegsiterClass< T > {}; \

namespace UserNs1 {
namespace UserNs2 {
namespace UserNs3 {
struct UserTypeA {};
REGISTER_CLASS_WITH_LIB_V2(UserTypeA); /* error:
'LibNs1::LibNs2::RegsiterClass<UserNs1::UserNs2::UserNs3::UserTypeA>' :
symbol cannot be defined within namespace 'UserNs3' */

struct UserTypeB {};
REGISTER_CLASS_WITH_LIB_V2(UserTypeB);

struct UserTypeC {};
REGISTER_CLASS_WITH_LIB_V2(UserTypeC);
}}}

//Works but cumbersome for users
REGISTER_CLASS_WITH_LIB_V1(UserNs1::UserNs2::UserNs3::UserTypeA);
REGISTER_CLASS_WITH_LIB_V1(UserNs1::UserNs2::UserNs3::UserTypeB);
REGISTER_CLASS_WITH_LIB_V1(UserNs1::UserNs2::UserNs3::UserTypeC);

</CODE>

For example this issue can be seen with the boost::serialize
BOOST_CLASS_EXPORT macro.

Cheers, Patrik
 
V

Victor Bazarov

A common pattern is to have users register their classes with a
framework. By having users specialize a templated class, located in
the framework namespace, with their user types. To make this easier
for users a macro function is often used. The problem becomes that
users can not use this macro from within any user namespaces. This
makes the macro less useful. Is there a way around this?

If a class template is declared in a namespace, its specializations need
to be in the same namespace, otherwise they are not its specializations.
It's quite a limitation, but considering the rules for name lookup,
it's inevitable, I think.

Perhaps specializations aren't what you need. If you can explain what
you're trying to accomplish with the specializations, an alternative
solution could be worked out...
<CODE>

namespace LibNs1 {
namespace LibNs2 {
template<typename T>
struct RegsiterClass {};
}
}

//Works but expects to be called from root namespace which is
cumbersome for users
#define REGISTER_CLASS_WITH_LIB_V1(T) \
namespace LibNs1 { \
namespace LibNs2 { \
template<> \
struct RegsiterClass< T> {}; \
}} \

//does not work
#define REGISTER_CLASS_WITH_LIB_V2(T) \
template<> \
struct ::LibNs1::LibNs2::RegsiterClass< T> {}; \

namespace UserNs1 {
namespace UserNs2 {
namespace UserNs3 {
struct UserTypeA {};
REGISTER_CLASS_WITH_LIB_V2(UserTypeA); /* error:
'LibNs1::LibNs2::RegsiterClass<UserNs1::UserNs2::UserNs3::UserTypeA>' :
symbol cannot be defined within namespace 'UserNs3' */

struct UserTypeB {};
REGISTER_CLASS_WITH_LIB_V2(UserTypeB);

struct UserTypeC {};
REGISTER_CLASS_WITH_LIB_V2(UserTypeC);
}}}

//Works but cumbersome for users
REGISTER_CLASS_WITH_LIB_V1(UserNs1::UserNs2::UserNs3::UserTypeA);
REGISTER_CLASS_WITH_LIB_V1(UserNs1::UserNs2::UserNs3::UserTypeB);
REGISTER_CLASS_WITH_LIB_V1(UserNs1::UserNs2::UserNs3::UserTypeC);

</CODE>

For example this issue can be seen with the boost::serialize
BOOST_CLASS_EXPORT macro.

I am not familiar with that macro.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top