Problem (Abstract)
There is a macro that declares an overload of specific function. A trivial example is like this:
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.
Now, a problem rises when some_func
is put into a namespace like this:
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'
The error makes sense because declarations are only allowed inside namespace brackets. Yet obviously, inserting them into the macro doesn't work quite well:
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!
To sum up, I'd like to call this macro to exactly overload foo::some_func()
from everywhere, regardless of namespace called in. Is there any way to make it work reliably?
Problem (Concrete)
Concrete problem follows here FYI. Basically what I try to achieve is to make a namespaced version of compile-time registration trick posted by Roman Perepelitsa (see original post for more information about this: https://stackoverflow.com/a/21626087). The initial version I've tried is like this:
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, "")
Here, the problem is CTR_REGISTER_TYPE()
macro, which appends a type to a MPL-like vector related to a specific tag. The trick is done by combination of inheritance (ctr::Rank<>
) and overloading (ctr::GetTypes()
), so it is certain that overloaded version needs to be declared every time a type is registered at caller side.
The problem is, I'd like to make caller to be ANY namespace. For example, I tried to compile following code but failed:
#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'
I'd like to know any workaround is possible for this kind of problems. Thanks.