Указатель на член класса как параметр шаблона
Я хочу использовать указатель на член класса в качестве параметра шаблона, как в:
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>
, и если да, то как?
Связанный с этим вопрос, который не разрешил мой вопрос:
Ответы
Ответ 1
Это может быть решение в С++ 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>
Я использую это как промежуточное решение, пока не перейдем к С++ 17.
Ответ 2
Ответ на мой вопрос был предложен в этой статье для следующего предстоящего стандарта С++:
Этот синтаксис был предложен:
template<using typename T, T t>
struct some_struct { /* ... */ };
some_struct<&A::f> x;
Необходимость в новой синтаксической конструкции указывает, что вы не можете этого сделать.
Я надеюсь, что n3601 будет принят.: -)
Ответ 3
В С++ 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();
Ответ 4
Сделайте свой результат классом дочернего элемента вашего шаблона. предполагая, что элемент-указатель является объектом вашего результирующего класса публичным или любым другим, вы можете получить доступ к любым объектам, выполнив что-то вроде этого
template <stuff for this class> :: public result
{
blah
}