1

Say I have:

struct S{
    void f(int);
    float g(int,int);
    void h(int);
}

#define UID(w) /* how to do it? */

cout << UID(S::f);
cout << UID(S::g);
cout << UID(S::h);

I need some way of creating a unique number, string or address for each member.

This is because I'm going to be using:

#define BIND(foo) Generate<decltype(&foo), &foo>::call

u = & BIND(S::f)
v = & BIND(S::g)
w = & BIND(S::h)

i.e. BIND generates an associated C-style function

Here is a sketch of the generator:

template< typename F f >
struct Generate {}

template < typename R,  typename ...Arg,  R(S::*target)(Arg...) >
struct Generate< R(S::*)(Arg...),target >
{
    static R call( PyObject* self, Arg... carg)
    {
        cout << ??? // the name, e.g. 'S::b'

I need this function to cout the name of the S::foo that generated it.

So the second half of the question is: how can I recover the same UID from inside call?

The reason I'm trying to create UIDs is so that I can make a:

static std::map<void*, std::string> names_map;

Then I can modify my:

#define BIND(foo) Generate<decltype(&foo), &foo>::call; \
                  names_map[ UID(foo) ] = std::string(#foo);

    static R call( PyObject* self, Arg... carg)
    {
        cout << names_map[ UID(  R(S::*target)(Arg...)  ) ];

But how to actually do this?

I've put together a testcase on coliru -- can anyone make it work?

P i
  • 29,020
  • 36
  • 159
  • 267

1 Answers1

3

This sounds like an XY problem. What you actually need is a way to associate a particular type (Generate<...>) to something that can be used as a key in a map. There is a standard way to do that - it's called std::type_index.

static std::map<std::type_index, std::string> names_map;

/* ... */

template <typename R, typename... Arg, R(Base::*target)(Arg...)>
struct Generate< R(Base::*)(Arg...), target >
{
    static void call() 
    {
        std::cout << "TARG:" << names_map[ std::type_index( typeid(Generate) ) ] << std::endl;
    }
};

#define BIND(fp, cxx_target) \
                            fp = &Generate< decltype(&cxx_target), &cxx_target >::call; \
                            names_map[ std::type_index(typeid(Generate< decltype(&cxx_target), &cxx_target >)) ] = std::string(#cxx_target);

Demo.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • That's fantastic - Thankyou! I just noticed it can be made symmetrical by using `std::type_index(typeid(decltype(x)))` -- [here](http://coliru.stacked-crooked.com/a/3495a0357ee659d5) (is there any way to improve upon the #define?) – P i Jan 13 '15 at 00:56
  • @Pi Don't do that - that indexes on the *type* of the pointer to member function only. Note how your first call is printing `TARG:Base::h` when it should print `TARG:Base::f`? The code in my answer indexes on the type of `Generate<...>`, which incorporates both the type of the pointer to member function and the *value*. – T.C. Jan 13 '15 at 01:02
  • aiee. I should have looked at the output before posting that. [Fixed](http://coliru.stacked-crooked.com/a/a6dee3e43e3dd0f2). – P i Jan 13 '15 at 01:22