这是我的问题:在标题中我定义了一个结构模板type_to_string
,它旨在定义一个对应于给定类型参数的字符串:
namespace foo {
template <typename T>
struct type_to_string
{
static const char * value;
};
}
template <typename T>
const char * foo::type_to_string<T>::value = "???";
我还为字符串定义了一个默认值。
现在,我想使用宏来定义新类型:
#define CREATE_ID(name) \
struct name; \
\
template<> \
const char * foo::type_to_string<name>::value = #name;
问题在于我希望宏可以在名称空间中使用,如:
namespace bar
{
CREATE_ID(baz)
}
这是不可能的,因为必须在包含type_to_string<T>::value
的命名空间中定义foo
。
以下是我得到的编译错误:
[COMEAU 4.3.10.1] error: member "foo::type_to_string<T>::value [with T=bar::baz]"
cannot be specialized in the current scope
[VISUAL C++ 2008] error C2888: 'const char *foo::type_to_string<T>::value' :
symbol cannot be defined within namespace 'bar'
with
[
T=bar::baz
]
奇怪的是,GCC 4.3.5(MinGW版本)不会产生任何错误。
有没有人知道这方面的解决方法,可能是通过使用一些我不知道的查找规则(即在宏中声明type_to_string
,以便每个命名空间都有自己的版本,或类似的东西)?< / p>
答案 0 :(得分:9)
根据C ++标准14.7.3 / 2:
显式特化应在模板所属的命名空间中声明,或者用于 成员模板,在封闭类或封闭类模板所属的命名空间中。 类模板的成员函数,成员类或静态数据成员的显式特化 应在类模板所属的命名空间中声明。这样的声明也可能 是一个定义。如果声明不是定义,专业化可在后面的名称中定义 - 声明显式特化的空间,或者包含其中的显式特化的空间 声明了明确的专业化。
您可以写下类似内容:
#define DECL_ID(name) \
struct name;
#define CREATE_ID(name) \
template<> \
const char * foo::type_to_string<name>::value = #name;
namespace bar { namespace bar2 {
DECL_ID(baz)
} }
CREATE_ID(bar::bar2::baz)
或者
#define CREATE_ID(ns, name) \
namespace ns { struct name; } \
\
template<> \
const char * foo::type_to_string<ns::name>::value = #name;
CREATE_ID(bar, baz)
第三个选项是前两个的叠加。它允许在value
中使用不合格的名称(如果需要):
#define DECL_ID(name) \
struct name;
#define CREATE_ID(ns, name) \
template<> \
const char * foo::type_to_string<ns::name>::value = #name;
namespace bar { namespace bar2 {
DECL_ID(baz)
} }
CREATE_ID(bar::bar2, baz)
答案 1 :(得分:1)
这是我使用的解决方案,使用Boost.Preprocessor:
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#define BEGIN_NS(r, _, elem) namespace elem {
#define CLOSE_NS(z, n, _) }
#define APPEND_NS(r, _, elem) elem::
#define CREATE_ID(ns_list, name) \
\
BOOST_PP_SEQ_FOR_EACH(BEGIN_NS, ~, ns_list) \
struct name; \
BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(ns_list), CLOSE_NS, ~) \
\
template<> \
const char * devs::type_to_string< \
BOOST_PP_SEQ_FOR_EACH(APPEND_NS, ~, ns_list)name \
>::value = #name;
必须在任何名称空间之外使用,如下所示:
CREATE_ID((bar) (bar2), baz)
似乎很奇怪我必须定义一个宏只重复n次字符'}',如果有人有更优雅的方式这样做,随时发表评论!