有一个宏声明特定功能的重载。一个微不足道的例子是这样的:
void some_func();
#define DECLARE_some_func(ParamType) void some_func(ParamType)
DECLARE_some_func(char); //OK. 'void some_func(char)' is declared.
DECLARE_some_func(bool); //OK. 'void some_func(bool)' is declared.
现在,当some_func
被放入这样的命名空间时,问题就出现了:
namespace foo {
void some_func();
}
#define FOO_DECLARE_some_func(ParamType) void ::foo::some_func(ParamType)
FOO_DECLARE_some_func(char);
//ERROR! 'void foo::some_func(char)' should have been declared inside 'foo'
错误有意义,因为声明只允许在命名空间括号内。显然,将它们插入宏中并不能很好地工作:
namespace foo {
void some_func();
}
#define FOO_DECLARE_some_func(ParamType) \
namespace foo { \
void some_func(ParamType); \
} \
static_assert(true, "")
FOO_DECLARE_some_func(char); //OK. 'void foo::some_func(char)' is declared.
namespace bar {
struct baz_type {};
FOO_DECLARE_some_func(baz_type);
//WRONG! It declares ::bar::foo::some_func instead of ::foo::some_func
}
decltype(foo::some_func(bar::baz_type())) *abc; //ERROR!
总而言之,我想调用此宏来完全从任何地方重载foo::some_func()
,无论调用哪个命名空间。有没有办法让它可靠地工作?
这里有具体问题供参考。基本上我尝试实现的是制作Roman Perepelitsa发布的编译时注册技巧的命名空间版本(有关此内容的更多信息,请参阅原始帖子:https://stackoverflow.com/a/21626087)。我尝试的初始版本是这样的:
namespace ctr {
// The maximum number of types that can be registered with the same tag.
constexpr int kMaxRegisteredTypes = 10;
template <int N>
struct Rank : Rank<N - 1> {};
template <>
struct Rank<0> {};
// Poor man's MPL vector.
template <class... Ts>
struct TypeList {
static const int size = sizeof...(Ts);
};
template <class List, class T>
struct Append;
template <class... Ts, class T>
struct Append<TypeList<Ts...>, T> {
typedef TypeList<Ts..., T> type;
};
template <class Tag>
TypeList<> GetTypes(Tag*, Rank<0>) { return {}; }
}
// Evaluates to TypeList of all types previously registered with
// REGISTER_TYPE macro with the same tag.
#define CTR_GET_REGISTERED_TYPES(Tag) \
decltype(ctr::GetTypes(static_cast<Tag*>(nullptr), ctr::Rank<kMaxRegisteredTypes>()))
// Appends Type to GET_REGISTERED_TYPES(Tag).
#define CTR_REGISTER_TYPE(Tag, Type) \
inline ctr::Append<CTR_GET_REGISTERED_TYPES(Tag), Type>::type \
ctr::GetTypes(Tag*, ctr::Rank<CTR_GET_REGISTERED_TYPES(Tag)::size + 1>) { \
return {}; \
} \
static_assert(true, "")
此处,问题是CTR_REGISTER_TYPE()
宏,它将类型附加到与特定标记相关的类MPL向量。诀窍是通过继承(ctr::Rank<>
)和重载(ctr::GetTypes()
)的组合来完成的,因此每次在调用方注册类型时都需要声明重载版本。
问题是,我想让调用者成为任何命名空间。例如,我尝试编译以下代码但失败了:
#include "ctr.hpp"
namespace foo {
struct integers;
}
CTR_REGISTER_TYPE(foo::integers, int);
//ERROR:
// 'ctr::Append<ctr::Typelist<>, int>::type
// ctr::GetTypes(foo::integers*, ctr::Rank<1>)'
// should have been declared inside 'ctr'
我想知道这种问题可能有任何解决方法。感谢。