Pointer to class member as a template parameter
Asked Answered
G

4

33

I want to use a pointer to a class member as a template parameter as in:

template <class Class, class Result, Result Class::*Member>
struct MyStruct {
    // ...
};

Using this struct like MyStruct<SomeClass, SomeResult, &SomeClass::value> variable works just fine, but I don't like that I have to specify SomeClass and SomeResult.

I would like to use MyStruct<&SomeClass::value> variable if that is possible, but without losing the ability to pass any class and have any result type.

I tried the following, but the syntax is illegal:

template <class Class, class Result>
template <Result Class::*Member>
struct MyStruct {
    // ...
};

error: too many template-parameter-lists

I tried using a helper function (that does actually work in Clang but is refused by GCC):

template <class Class, class Result>
static constexpr auto makeMyStruct(Result Class::*member) ->
MyStruct<Class, Result, member> {
    // ...
}

error: use of parameter `member' outside function body
error: template argument 3 is invalid

Is it possible to have a simple MyStruct<&SomeClass::value>, and if so, how?

Related question that did not solve my question:

Golightly answered 1/3, 2013 at 1:13 Comment(7)
Dup? #5628621Counterblast
@Counterblast I'm not sure if my question boils down to that other question. Mine is far more narrow, and I'd be not too happy using a macro.Golightly
The term is pointer-to-member, not reference to member. References and pointers are quite different in the language (well, not that different, but still not the same)Paquin
The issue with your helper function is the use of the runtime value member as a template argument, which must be known at compile-time to instantiate the template. If you were to change MyStruct to take the Result Class::*member as a constructor parameter instead of template parameter then it works fine.Chasechaser
@boycy, you are missing the point … isocpp.org/files/papers/n3601.html proposes a solution to the problem.Golightly
@Kay - I understood what you were trying to achieve & how N3601 provides you a solution. I wished to add for the benefit of anyone else visiting (and you, in case you were unaware) why the helper function wouldn't compile. I'm confused by Clang accepting it though...Chasechaser
@Chasechaser I did not mention it properly, but the argument to the ctor should be known at compile time. As in auto x = makeMyStruct(&SomeStruct::some_member);. N3601 comes in handy in this case.Golightly
T
19

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();
Tittle answered 4/1, 2017 at 23:43 Comment(0)
G
11

An answer to my question was proposed in this paper for the next upcoming C++ standard:

This syntax was proposed:

template<using typename T, T t>
struct some_struct { /* ... */ };

some_struct<&A::f> x;

The need for a new syntactical construct indicates that you cannot do that by now.

I hope n3601 will be accepted. :-)

Golightly answered 19/3, 2013 at 20:5 Comment(0)
V
8

This could be a solution in C++11:

You can define the following generic type traits:

template<class T>
struct remove_member_pointer {
  typedef T type;
};

template<class Parent, class T> 
struct remove_member_pointer<T Parent::*> {
  typedef T type;
};

template<class T>
struct baseof_member_pointer {
  typedef T type;
};

template<class Parent, class T>
struct baseof_member_pointer<T Parent::*> {
  typedef Parent type;
};

Now you can define an additional, 4-line wrapper macro for every struct:

template<class Class, class Result, Result Class::*Member>
struct _MyStruct {
  // ...
};

#define MyStruct(MemberPtr) \
  _MyStruct<baseof_member_pointer<decltype(MemberPtr)>::type, \
            remove_member_pointer<decltype(MemberPtr)>::type, \
            MemberPtr>

... and use it in the following way:

MyStruct(&SomeClass::value)  myStruct; // <-- object of type MyStruct<&SomeClass:value>

I use this as an intermediate solution, until we switch to C++17.

Vaisya answered 19/7, 2017 at 7:47 Comment(0)
S
-8

Make your result class a child of your template class. assuming the pointer member is an object of your result class in public or whatever, you can access any objects by doing something like this

template <stuff for this class> :: public result
{
    blah
}
Salcedo answered 3/3, 2013 at 5:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.