¿Es posible tener una variable miembro, que pueda calcular el puntero al objeto contenedor desde el puntero a sí mismo (en su método)?Variable miembro de clase C++ que conoce su propio desplazamiento
Tengamos una interfaz de llamada extranjera envuelta en API de la siguiente manera:
template <typename Class, MethodId Id, typename Signature>
class MethodProxy;
template <typename Class, MethodId Id, typename ReturnT, typename Arg1T>
class MethodProxy<Class, Id, ReturnT()(Arg1T) {
public:
ReturnT operator()(Class &invocant, Arg1T arg1);
};
y de manera similar para otros números de argumentos de 0 a N. Para cada clase en el lado exterior, una clase de C++ se declara con cierta rasgos y esta plantilla utiliza esos rasgos (y más rasgos para los tipos de argumento) para encontrar e invocar el método extraño. Esto puede ser usado como:
Foo foo;
MethodProxy<Foo, barId, void()(int)> bar;
bar(foo, 5);
Ahora lo que me gustaría hacer es definir Foo
de tal manera, que puedo llamar como:
Foo foo;
foo.bar(5);
sin repetir la firma varias veces. (obviamente crear un miembro estático y envolver la llamada en un método es simple, a la derecha). Bueno, de hecho, eso es aún más fácil:
template <typename Class, MethodId Id, typename Signature>
class MethodMember;
template <typename Class, MethodId Id, typename ReturnT, typename Arg1T>
class MethodMember<Class, Id, ReturnT()(Arg1T) {
MethodProxy<Class, Id, Signature> method;
Class &owner;
public:
MethodMember(Class &owner) : owner(owner) {}
ReturnT operator()(Arg1T arg1) { return method(owner, arg1); }
};
Eso significa sin embargo el objeto terminará contiene muchas copias del puntero a sí mismo. Así que estoy buscando una manera de hacer que estas instancias puedan calcular el puntero del propietario desde this
y algunos argumentos adicionales de la plantilla.
Estaba pensando en la línea de
template <typename Class, size_t Offset, ...>
class Member {
Class *owner() {
return reinterpret_cast<Class *>(
reinterpret_cast<char *>(this) - Offset);
}
...
};
class Foo {
Member<Foo, offsetof(Foo, member), ...> member;
...
};
pero esto se queja de que es Foo tipo incompleto en el punto.
Sí, sé que offsetof
se supone que solo funciona para los tipos "POD", pero en la práctica para cualquier miembro no virtual, que así sea, funciona. De manera similar, he intentado pasar puntero-a- (ese) -miembro (usando clase base ficticia) en ese argumento, pero eso tampoco funciona.
Tenga en cuenta que si esto funcionó, también se podría usar para implementar propiedades de tipo C# delegando a métodos de la clase contenedora.
Sé cómo hacer los métodos de envoltura mencionados anteriormente con boost.preprocessor, pero las listas de argumentos deberían especificarse en una forma extraña. Sé cómo escribir macro para generar envoltorios genéricos a través de plantillas, pero eso probablemente dará diagnósticos pobres. También sería trivial si las llamadas pudieran verse como foo.bar()(5)
. Pero me gustaría saber si algún truco inteligente sería posible (además, solo ese truco ingenioso sería probablemente útil para las propiedades).
Nota: El tipo de miembro no puede estar especializado ni en un puntero de miembro ni en un desplazamiento, porque el tipo debe conocerse antes de que se pueda asignar el desplazamiento. Esto se debe a que el tipo puede afectar la alineación requerida (considere la especialización explícita/parcial).
leí que en varias ocasiones, pero aún no consigue lo que quiere hacer, qué quiere una clase genérica * propiedad * que es consciente de ¿Qué posee? De ser así, ¿por qué debería saber qué lo posee? Me imagino que todo lo que una propiedad realmente necesita es la capacidad de aceptar un valor y devolver el valor. – Nim
Yo tampoco lo entiendo ...¿Que estás tratando de hacer? – mfontanini
@Nim: Sí, quiero una clase genérica de "propiedad" que sepa de qué se trata. Para la propiedad es necesario si el valor de la propiedad debe * calcularse *. En mi caso, sin embargo, es un funtor que necesita pasar el puntero al propietario al método subyacente. –