C ++ - 重载外部命名空间

时间:2015-01-10 15:13:10

标签: c++ macros namespaces overloading declaration

问题(摘要)

有一个宏声明特定功能的重载。一个微不足道的例子是这样的:

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'

我想知道这种问题可能有任何解决方法。感谢。

0 个答案:

没有答案