c++ - punteros - Puntero a miembro de clase como parámetro de plantilla
this-> en c++ (4)
Quiero usar un puntero a un miembro de la clase como un parámetro de plantilla como en:
template <class Class, class Result, Result Class::*Member>
struct MyStruct {
// ...
};
El uso de esta estructura como MyStruct<SomeClass, SomeResult, &SomeClass::value> variable
funciona bien, pero no me gusta que tenga que especificar SomeClass
y SomeResult
.
Me gustaría usar la MyStruct<&SomeClass::value> variable
si es posible, pero sin perder la capacidad de pasar cualquier clase y tener cualquier tipo de resultado.
Intenté lo siguiente, pero la sintaxis es ilegal:
template <class Class, class Result>
template <Result Class::*Member>
struct MyStruct {
// ...
};
error: demasiadas plantillas-listas-parametros
Intenté usar una función auxiliar (que en realidad funciona en Clang pero GCC lo rechaza):
template <class Class, class Result>
static constexpr auto makeMyStruct(Result Class::*member) ->
MyStruct<Class, Result, member> {
// ...
}
error: uso del parámetro `miembro ''fuera del cuerpo de la función
error: el argumento de la plantilla 3 no es válido
¿Es posible tener un simple MyStruct<&SomeClass::value>
, y si es así, cómo?
Pregunta relacionada que no resolvió mi pregunta:
- Puntero a miembro de clase como parámetro de plantilla
- Error de C ++ 0x con constexpr y función de plantilla de retorno
En c ++ 17, con la adición de auto
en los argumentos de la plantilla ( P0127) , creo que ahora puede hacer:
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();
En este documento se propuso una respuesta a mi pregunta para el próximo estándar de C ++:
Esta sintaxis fue propuesta:
template<using typename T, T t>
struct some_struct { /* ... */ };
some_struct<&A::f> x;
La necesidad de una nueva construcción sintáctica indica que no se puede hacer eso ahora.
Espero que n3601 sea aceptado. :-)
Esto podría ser una solución en C ++ 11:
Puede definir los siguientes rasgos de tipo genérico:
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;
};
Ahora puede definir una macro adicional de 4 líneas para cada estructura:
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>
... y utilízalo de la siguiente manera:
MyStruct(&SomeClass::value) myStruct; // <-- object of type MyStruct<&SomeClass:value>
Utilizo esto como una solución intermedia, hasta que cambiamos a C ++ 17.
Haz de tu clase de resultado un hijo de tu clase de plantilla. Suponiendo que el miembro puntero es un objeto de su clase de resultado en público o lo que sea, puede acceder a cualquier objeto haciendo algo como esto
template <stuff for this class> :: public result
{
blah
}