Kamajii
Kamajii

Reputation: 1878

Deducing pointer-to-member template arguments

Consider classes with member variables, like these:

struct A {
    int a;
    char b;
};

struct B {
    double c;
    bool d;
};

Is it possible to declare a template class that accepts as its template argument a pointer-to-member-object to any one of the members declared in the above classes? A class that accepts a generic pointer-to-member-object could be declared and used as follows:

template<typename Class, typename Type, Type (Class::*Member)>
struct Magic
{ };

// Usage:
typedef Magic<A, int, &A::a> MagicWithA_a;

Unfortunately it is quite cumbersome having to pass in the Class and Type template arguments every time to make the final pointer work.

Is there any way to have these arguments deduced by partial specialization, for example? That is, how can the Magic class be declared to make the below definitions work?

typedef Magic<&B::c> MagicWithB_c;
typedef Magic<&A::b> MagicWithA_b;

Upvotes: 4

Views: 885

Answers (2)

You can shorten it somewhat with specializations, yes. And if you don't mind resorting to macros you can have almost the syntax you want with . First, a primary template specialization:

template<typename T, T pm>
struct MagicImpl; // Undefined for most types

Then a partial specialization for pointers to members, where we can freely add the parameters we wish to be deduced:

template<class Class, typename Type>
struct MagicImpl<Type Class::*, Type (Class::*Member)> {
};

And finally, we need to employ decltype to get the pointer to member type out of the pointer-to-member expression, which we hide behind the aforementioned macro:

#define MAGIC(...) MagicImpl<decltype(__VA_ARGS__), __VA_ARGS__>

And you can use it as follows:

typedef MAGIC(&B::c) MagicWithB_c;
typedef MAGIC(&A::b) MagicWithA_b;

Upvotes: 3

user7860670
user7860670

Reputation: 37487

With C++17 you can use auto non-type template parameter:

template<auto p_member>
struct Magic
{ };

Before C++17 only the longer variant that you've implemented would work.

Upvotes: 7

Related Questions