Указатель на член класса в качестве параметра шаблона


Я хочу использовать указатель на член класса в качестве параметра шаблона, как в:

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

Использование этой структуры как MyStruct<SomeClass, SomeResult, &SomeClass::value> variable работает просто отлично, но мне не нравится, что я должен указать SomeClass и SomeResult.

Я хотел бы использовать MyStruct<&SomeClass::value> variable, если это возможно, но без потери способности передавать любой класс и иметь любой тип результата.

Я попробовал следующее, но синтаксис незаконен:

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

Ошибка: слишком много списков параметров шаблона

Я попробовал использовать вспомогательная функция (которая действительно работает в Clang, но отвергается GCC):

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

Ошибка: использование параметра 'member' вне тела функции
ошибка: аргумент шаблона 3 недопустим

Возможно ли иметь простой MyStruct<&SomeClass::value>, и если да, то как?

Связанный вопрос, который не решил мой вопрос:

4 16

4 ответа:

Это может быть решением в C++11:

Можно определить следующие признаки универсального типа:

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;
};
Теперь вы можете определить дополнительный 4-строчный макрос-оболочку для каждой структуры:
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>

... и используйте его следующим образом:

MyStruct(&SomeClass::value)  myStruct; // <-- object of type MyStruct<&SomeClass:value>
Я использую это как промежуточное решение, пока мы не перейдем на C++17.

Ответ на мой вопрос был предложен в этой статье для следующего предстоящего стандарта C++:

Был предложен следующий синтаксис:

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

some_struct<&A::f> x;

Необходимость в новой синтаксической конструкции указывает на то, что вы не можете сделать это сейчас.

Я надеюсь, что n3601 будет принят. :- )

В c++17, с добавлением auto в аргументах шаблона (P0127) , я думаю, что теперь вы можете сделать:

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();

Сделайте класс результата дочерним по отношению к классу шаблона. предполагая, что член указателя является объектом вашего результирующего класса в public или любом другом, вы можете получить доступ к любым объектам, сделав что-то вроде этого

template <stuff for this class> :: public result
{
    blah
}