È possibile avere una variabile membro, che sarebbe in grado di calcolare il puntatore all'oggetto contenitore dal puntatore a se stesso (nel suo metodo)?Variabile membro della classe C++ che conosce il proprio offset
Diamo un'interfaccia chiamata estera avvolto in API simili:
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);
};
e similmente per altri numeri di argomenti da 0 a N. Per ogni classe sul lato straniero, una classe C++ è dichiarata con alcuni tratti e questo modello usa quei tratti (e più tratti per i tipi di argomento) per trovare e invocare il metodo straniero. Questo può essere usato come:
Foo foo;
MethodProxy<Foo, barId, void()(int)> bar;
bar(foo, 5);
Ora quello che vorrei fare è definire Foo
in modo tale, che io possa chiamare come:
Foo foo;
foo.bar(5);
senza ripetere la firma più volte. (ovviamente creare un membro statico e avvolgere la chiamata in un metodo è semplice, giusto). Beh, in effetti, che è ancora facile:
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); }
};
Che però significa che l'oggetto finirà che contiene molte copie di puntatore a se stesso. Quindi sto cercando un modo per rendere queste istanze in grado di calcolare il puntatore del proprietario da this
e alcuni argomenti del modello aggiuntivi.
Stavo pensando lungo le linee di
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;
...
};
ma questo si lamenta che Foo è tipo incompleto al punto.
Sì, so che si suppone che offsetof
funzioni solo per i tipi "POD", ma in pratica per qualsiasi membro non virtuale, che sarà, funziona. Allo stesso modo ho cercato di passare da pointer a to (that) -member (usando dummy base-class) in quell'argomento, ma anche questo non funziona.
Nota: se questo ha funzionato, potrebbe anche essere usato per implementare proprietà C# -like che delegano ai metodi della classe contenente.
So come eseguire i metodi wrapper menzionati sopra con boost.preprocessor, ma gli elenchi di argomenti dovrebbero essere specificati in una forma strana. So come scrivere macro per generare wrapper generici tramite template, ma questo probabilmente darebbe una scarsa diagnostica. Sarebbe anche banale se le chiamate potessero assomigliare a foo.bar()(5)
. Ma mi piacerebbe sapere se un trucco intelligente sarebbe possibile (in più solo un trucco così intelligente sarebbe probabilmente utilizzabile anche per le proprietà).
Nota: il tipo di membro non può essere effettivamente specializzato né su un puntatore a esso né su un offset, poiché il tipo deve essere noto prima di poter assegnare quell'offset. Questo perché il tipo può influenzare l'allineamento richiesto (considerare la specializzazione esplicita/parciale).
ho letto che molte volte, ma ancora non si ottiene ciò che si vuole fare, vuoi un generico di classe * proprietà * che è a conoscenza di a cosa serve - se sì, perché dovrebbe sapere cosa lo possiede? Dovrei immaginare che tutto ciò di cui una proprietà ha veramente bisogno è la capacità di accettare un valore e restituire il valore? – Nim
Non capisco neanche ..Cosa stai cercando di fare? – mfontanini
@Nim: Sì, voglio una classe generica di "proprietà" che sia a conoscenza di cosa lo possiede. Per la proprietà è necessario se il valore della proprietà deve essere * calcolato *. Nel mio caso è tuttavia un funtore che deve passare il puntatore al proprietario al metodo sottostante. –