问题
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;
回答1:
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.
回答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 c++11. 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;
来源:https://stackoverflow.com/questions/48478886/deducing-pointer-to-member-template-arguments