Переменная-член класса C ++, знающая собственное смещение.

Можно ли иметь переменную-член, которая могла бы вычислять указатель на содержащий объект из указателя на себя (в его методе)?

Давайте иметь интерфейс внешнего вызова, обернутый в API следующим образом:

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

и аналогично для другого числа аргументов от 0 до N. Для каждого класса на внешней стороне объявлен один класс C ++ с некоторыми характеристиками, и этот шаблон использует эти характеристики (и другие характеристики для типов аргументов) для поиска и вызова зарубежный метод. Это можно использовать как:

Foo foo;
MethodProxy<Foo, barId, void ()(int)> bar;
bar(foo, 5);

Теперь я хотел бы определить Foo таким образом, чтобы я мог вызывать как:

Foo foo;
foo.bar(5);

, не повторяя подпись несколько раз. (очевидно, что создать статический член и обернуть вызов в метод просто, верно). На самом деле, это все еще просто:

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

Однако это означает, что в конечном итоге объект будет содержать множество копий указателя на самого себя. Поэтому я ищу способ сделать так, чтобы эти экземпляры могли вычислять указатель владельца из this и некоторых дополнительных аргументов шаблона.

Я думал примерно так же, как в

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;
    ...
};

, но он жалуется на то, что Foo является неполным типом на данный момент.

Да, я знаю, что offsetof должен работать только для типов «POD», но на практике для любого не виртуального члена, которым это будет, работает. Я аналогичным образом пытался передать указатель на (этого) члена (используя фиктивный базовый класс) в этом аргументе, но это тоже не сработало.

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

Я знаю, как выполнять упомянутые выше методы-оболочки с помощью boost.preprocessor, но списки аргументов должны быть указаны в странной форме. Я знаю, как написать макрос для создания универсальных оболочек с помощью шаблонов, но это, вероятно, даст плохую диагностику. Было бы также тривиально, если бы вызовы выглядели как foo.bar () (5) . Но я хотел бы знать, возможен ли какой-нибудь хитрый трюк (плюс только такой хитрый трюк, вероятно, можно было бы использовать и для свойств).

Примечание: тип члена не может быть фактически специализирован ни на указателе члена, ни на это смещение, потому что тип должен быть известен до того, как это смещение может быть назначено. Это потому, что тип может повлиять на требуемое выравнивание (рассмотрите явную / частичную специализацию).

11
задан Jarod42 14 June 2014 в 19:59
поделиться