Pointer to Class Member as a Template Parameter

Pointer to class member as template parameter

From the standard:

A non-type template-parameter shall have one of the following (optionally cv-qualified) types:

  • integral or enumeration type,
  • pointer to object or pointer to function,
  • reference to object or reference to function,
  • pointer to member.

So it is allowed, and seems to work on g++ like this:

template <Dog Person::*ptr>
struct Strange { ... };

Passing a pointer-to-class-member as a template parameter

You can't do just test<&AA::type>, since you'd need to also tell the function template what type of pointer-to-member you're expecting. The typical pattern is:

template <class M, M member, class T> // deduced go last
void test(T& a) {
cout << (a.*member);
}

With usage:

test<decltype(&AA::type), &AA::type>

I believe there's currently a proposal to reduce the verbosity there, but until then, it's not the worst thing in the world, and you could always:

#define TYPE_AND_VAL(foo) decltype(foo), foo
test<TYPE_AND_VAL(&AA::type)>

That proposal I mentioned is in C++17, and will allow you to do:

template <auto member, class T>
void test(T& a) {
cout << (a.*member);
}

test<&AA::type>(a);

Pointer to class member as a template parameter

In c++17, with the addition of auto in template arguments (P0127), I think you can now do:

template<auto value>
struct MyStruct {};

template<typename Class, typename Result, Result Class::* value>
struct MyStruct<value> {
// add members using Class, Result, and value here
using containing_type = Class;
};

typename MyStruct<&Something::theotherthing>::containing_type x = Something();

Passing member function pointer as template parameter

template<typename F>
void call_func(F func) {
(wrapped.*func)();
}

then call like this:

wr.call_func(&some_class::some_func);

If you want to use the return value too, you'll need this:

template<typename F>
auto call_func(F func) -> decltype((std::declval<T>().*func)()) {
return (wrapped.*func)();
}

If you have C++14, you can omit the -> decltype(...) part and use decltype(auto) as the return value.

If you also want to pass functions, you can use variadic templates and forwarding for that.

template<typename F, typename... Args>
decltype(auto) call_func(F func, Args&&... args) {
return (wrapped.*func)(std::forward<Args>(args)...);
}

Deducing pointer-to-member template arguments

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.

Inferring type and class when passing a pointer to data member as a non-type template argument

You can use a helper to get the type of the class and the member from the type of a member pointer:

template <typename T> struct type_from_member;

template <typename Cls,typename M>
struct type_from_member<M Cls::*> {
using class_type = Cls;
using member_type = M;
};

Then you can use auto and inherit from the helper:

template <auto member> struct Mem : type_from_member<decltype(member)> {};

using B = Mem<&Struct::x>;

static_assert( std::is_same_v<B::member_type,int>);
static_assert( std::is_same_v<B::class_type,Struct>);

Pointers to member as variadic template parameters

In C++14, you can use another level of indirection to do that:

struct A {
int a;
float b;
};

template<typename... T>
struct Bar {
template <T A::*... params>
struct Foo {
void Bar(A *obj) {
void *members[] { (&(obj->*params))... };
// ... do something ...
(void)members;
}
};
};

int main() {
A a;

Bar<int, float>::Foo<&A::a, &A::b> foo;
foo.Bar(&a);
}

auto keyword (introduced with the C++17 for non-type template parameters, as you mentioned) solves more or less this kind of issues. Think of std::integral_constant and how would it be more user-friendly if you hadn't to specify each time the type as the first argument...



Related Topics



Leave a reply



Submit