1

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.

Community
  • 1
  • 1
nedsociety
  • 88
  • 8
  • 1
    If the macro is overloading a function in the namespace foo it makes no sense to place that macro inside of another namespace to begin with. You can always take the namespace as another argument to the macro, but that won't prevent you from placing the macro inside of the wrong namespace. – mbgda Jan 10 '15 at 15:20
  • 1
    If you're already in the wrong namespace, you can't go back to ::, there's no language feature that can do that short of closing the current namespaces and reopening them after. – tux3 Jan 10 '15 at 15:22
  • So you want to change the code to use namespaces, but allow the code to be invoked without specifying a namespace. What is the point, exactly? – Lightness Races in Orbit Jan 10 '15 at 15:25
  • More to the point, by wrapping the ctr namespace around that code, you're making it impossible to use. From what I can tell, it's not designed for types to be registered outside of the global namespace to begin with. It would need to be rewritten to use a different technique other than function overloading to do what you need. – mbgda Jan 10 '15 at 15:29
  • @mbgda, may I ask you different technique you're refering to? – nedsociety Jan 10 '15 at 15:52
  • @LightnessRacesinOrbit, For the purpose of the actual problem, please refer to the concrete version. There is a pretty good reason to namespace constructs like `Append`, `Rank` and `GetTypes` as these are very general names. A prefix might be added like `CompileTimeRegister_GetTypes` instead of namespace but it is rather ugly. – nedsociety Jan 10 '15 at 15:58

0 Answers0