Re[5]: указатель на под-член
От: rg45 СССР  
Дата: 16.12.09 16:55
Оценка: +1 :)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Здравствуйте, rg45, Вы писали:


R>>Для начала определим обобщенную функцию, которая по двум указателям — на член и на подчлен — возвращает их "суперпозицию", так сказать:


PD>М-да. Как говорится, зачем делать просто, если можно сделать сложно. Никак в этой задаче не обойтись без template, специальной функции и двух десятков строк...


PD>Или все же можно ? Я попробовал, получилось вроде не хуже.


PD>
PD>int mem = offsetof(B,z) + offsetof(A,x);
PD>int B::* p = (int B::*&)(mem);
PD>  B b;
PD>  b.*p = 123;
PD>



--
Справедливость выше закона. А человечность выше справедливости.
Re[4]: указатель на под-член
От: Кодт Россия  
Дата: 18.12.09 15:41
Оценка: 7 (1)
Здравствуйте, rg45, Вы писали:

R>Для начала определим обобщенную функцию, которая по двум указателям — на член и на подчлен — возвращает их "суперпозицию", так сказать:


Извините, что влезаю в дискуссию... А что, если с самого начала избавиться от такого явления, как указатель на член?

Указатель на член — это особая функция, на вход которой подают ссылку на объект, а на выходе — ссылка на другой объект.
Сделаем из него не особую, а обычную функцию.
template<class Host, class Member, Member Host::*mp>
Member& member(Host& host) { return host.*mp; }

// суперпозиция во время компиляции
template<class A, class B, class C, B&(*a2b)(A&), C&(*b2c)(B&)>
C& superposition(A& a) { return b2c(a2b(a)); }

struct P { int x, y; };
struct Q { P z; int t; };

int& (*get_t)(Q&) = member<Q,int,&Q::t>;
int& (*get_x)(Q&) = superposition<Q,P,int, member<Q,P,&Q::z>, member<P,int,&P::x> >;

Q q = { { 1, 2 }, 3 };

int& t = get_t(q);
int& x = get_x(q);


Здесь получилось нечто многословное, с явным указанием типов всех участников.
Можно подумать, как допилить до автоматического вывода. Возможно, завернуть в шаблоны классов...


И кстати, указатели на члены-данные прекрасно замыкаются в boost::bind / boost::function.
Понятно, что оверхед и всё такое, но может, у компилятора хватит ума проинлайнить — чтобы bind(&P::x, bind(&Q::z, _1))(q) превратилось в q.*(&Q::z).*(&P::x) — а оттуда в q.z.x ?
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re: указатель на под-член
От: tyomitch  
Дата: 16.12.09 12:12
Оценка: 1 (1)
Коллеги, возник ещё один вопрос по теме.
Как сделать указатель на "невидимый член" базового класса?
К примеру:

struct A { float w; int x; } ;
struct B { char y; } ;
struct C : public A, public B { } ;
B C::* p;
C c;


И цель — чтобы c.*p было эквивалентно (B)c

Опять же, кажется, что можно изхитриться и узнать смещение предка в потомке, а по нему сконструировать указатель?
Re[7]: указатель на под-член
От: Erop Россия  
Дата: 18.12.09 07:38
Оценка: 1 (1)
Здравствуйте, Pavel Dvorkin, Вы писали:

PD>Тем более, что твоя superposition будет, конечно, вынесена в хедер, а хедеры никто не смотрит.

Выделенный тезис представляется мне более чем сомнительным...

PD>В итоге... если что-то потом окажется не так, придется разбираться намного дольше. У меня же все ясно и недвусмысленно сказано.


Фишка вы том, что
1) в superposition можно организовать, вообще-то контроль типов.
2) можно организовать тестирование работоспособности этого хака, чтобы на платформе, где всё сломается, сразу и не собралось бы или не запустилось и т. д.
3) (на самом деле главное), когда понадобится переносить этот код на платформу, где хак будет немного другой (например, будут хранить в указателе на поле не смещение, а смещение + константа), то в варианте с superposition понадобится сделать условную компиляцию в одном месте, а у тебя всюду в клиентском коде. И объём правок, конечно разный.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[9]: указатель на под-член
От: Erop Россия  
Дата: 18.12.09 08:09
Оценка: 1 (1)
Здравствуйте, Pavel Dvorkin, Вы писали:


PD>Когда ты последний раз заглядывал в stdio.h ?

Ну он, во-первых, стандартный, и, во-вторых, я им вроде бы не пользуюсь к тому же...

PD>>>В итоге... если что-то потом окажется не так, придется разбираться намного дольше. У меня же все ясно и недвусмысленно сказано.


Если написать superposition достаточно аккуратно, то сразу будет понятно где разбираться...

PD>В общем, со многим можно согласиться, но лучше вообще это нигде не писать и не провоцировать, делая вид, что superposition — это честная функция, а не злобный хак


Ну так ясно, что без хака лучше
Но мы сравнивали не вариант с хаком и вариант без, а твой с superposition...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[4]: указатель на под-член
От: Pavel Dvorkin Россия  
Дата: 16.12.09 13:05
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>Для начала определим обобщенную функцию, которая по двум указателям — на член и на подчлен — возвращает их "суперпозицию", так сказать:


М-да. Как говорится, зачем делать просто, если можно сделать сложно. Никак в этой задаче не обойтись без template, специальной функции и двух десятков строк...

Или все же можно ? Я попробовал, получилось вроде не хуже.

int mem = offsetof(B,z) + offsetof(A,x);
int B::* p = (int B::*&)(mem);
  B b;
  b.*p = 123;
With best regards
Pavel Dvorkin
Re[6]: указатель на под-член
От: Pavel Dvorkin Россия  
Дата: 17.12.09 06:07
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>
  • Ну, во-первых, я конечно и сам люблю иногда загнуть, но в данном случае перебор: строк всего шесть, не считая двух фигурных скобок, а не пара десятков, как ты пишешь.

    Ладно, перебрал.

    R>
  • Во-вторых, эти шесть строк написаны один раз на все случаи жизни. Если хочешь сравнить, что проще, то честнее будет сравнивать простоту использования, а не реализации. А тут ты явно проигрываешь. Смотри сам, что проще и легче для восприятия:
    R>
    R>int B::* p = superposition(&B::z, &A::x);
    R>

    R>или
    R>
    R>int mem = offsetof(B,z) + offsetof(A,x);
    R>int B::* p = (int B::*&)(mem);
    R>

    R>???

    Я так думаю, что все же второе. По той простой причине, что в нем честно говорится, что тут делается. В то время как в твоем решении надо еще пробиться через эти 3 template и понять, что чему соответствует.

    R>Вдобавок, для вспомогательной переменной mem ты всякий раз будешь придумывать уникальное имя или будешь использовать одну на все случаи жизни? Это тоже к вопросу о простоте использования.


    Вообще-то интересный вопрос. Не совсем, правда, понятно, почему именно тут он у тебя возникает. Его можно и более в общем плане поставить — если нужна вспомогательная переменная для чего бы то ни было, будем пользоваться каждый раз одной и той же или же каждый раз надо заводить новую ? . Философский вопрос, что и говорить.


    R>
  • В-третьих, в твоем решении применяется макрос

    И что ? Ничего плохого я в этом не вижу.


    R>
  • В-четвертых, и это самое главное. Я с самого начала своего поста сказал, что данное решение — это хак. Только в моем решении этот хак тщательно локализован и спрятан под капот. Вызывающий код, не смотря на то, что он пользуется этим хаком чист как младенец. Ты же предлагаешь, эту нечисть размазать по всему клиентскому коду и тем самым подложить свинью тому, кому, не дай бог, прийдется ЭТО сопровождать.


    Ну-ну. То, что хак — согласен. Но хак, упрятанный под капот, ничем не лучше хака, который явно виден. Скорее наоборот, он говорит явно — внимание, это хак! Твой же вызывающий код, чистый аки новорожденный младенец, создает у меня ложное впечатление, что хака и нет вообще. Тем более, что твоя superposition будет, конечно, вынесена в хедер, а хедеры никто не смотрит. В итоге... если что-то потом окажется не так, придется разбираться намного дольше. У меня же все ясно и недвусмысленно сказано.
  • With best regards
    Pavel Dvorkin
    указатель на под-член
    От: tyomitch-cs  
    Дата: 12.12.09 19:14
    Оценка:
    Здравствуйте.

    У меня есть, к примеру:

    struct A { float w; int x; } ;
    struct B { char y; A z; } ;
    int B::* p;
    B b;


    Как мне теперь в переменную p запихнуть адрес поля B::z.x?
    Так, чтобы b.*p было эквивалентно b.z.x
    Если, по логике вещей, указатель на член -- это просто смещение от начала структуры, то это должно быть возможно, разве нет?
    pointer to member
    Re: указатель на под-член
    От: rg45 СССР  
    Дата: 12.12.09 20:49
    Оценка:
    Здравствуйте, tyomitch-cs, Вы писали:

    TC>Здравствуйте.


    TC>У меня есть, к примеру:


    TC>
    TC>struct A { float w; int x; } ;
    TC>struct B { char y; A z; } ;
    TC>int B::* p;
    TC>B b;
    TC>


    TC>Как мне теперь в переменную p запихнуть адрес поля B::z.x?

    TC>Так, чтобы b.*p было эквивалентно b.z.x

    Как-то чересчур уж жестко вопрос поставлен. Цель поставлена четко: чтобы было эквивалентно b.z.x. Форма выражения задана строго: b.*p. Определение p тоже не двусмысленно: int B::* p. Никакой степени свободы. В такой постановке вопроса ответ один: никак.

    TC>Если, по логике вещей, указатель на член -- это просто смещение от начала структуры, то это должно быть возможно, разве нет?


    Внутреннее устройство данных и то, как они расположены в памяти, в данном случае не имеют никакого значения, мало ли что с чем совпадает во внутреннем представлении. Здесь все упирается в семантику объявлений и выражений — int B::* обозначает: член класса B типа int, и не может быть использован для обращения к членам ни других типов, ни других классов.

    Если хочешь получить дельную подсказку, опиши задачу немного более верхнего уровня.
    --
    Справедливость выше закона. А человечность выше справедливости.
    Re[2]: указатель на под-член
    От: tyomitch-cs  
    Дата: 12.12.09 21:33
    Оценка:
    Здравствуйте, rg45, Вы писали:

    R>Внутреннее устройство данных и то, как они расположены в памяти, в данном случае не имеют никакого значения, мало ли что с чем совпадает во внутреннем представлении. Здесь все упирается в семантику объявлений и выражений — int B::* обозначает: член класса B типа int, и не может быть использован для обращения к членам ни других типов, ни других классов.


    Тип именно int. Хочу обратиться к элементу класса B типа int; единственная загвоздка, что он не напрямую член, а как-бы-подчлен.

    На данном этапе, меня бы даже устроил совет, как реализовать это через reinterpret_cast, лишь бы заработало.

    R>Если хочешь получить дельную подсказку, опиши задачу немного более верхнего уровня.


    Имеется template <class T, class K, K T::* pk> class Index, добавляющий объект типа T в индекс по полю pk типа K.
    Имеется желание применить этот шаблон к структуре по её подчлену.
    Re: указатель на под-член
    От: Caracrist https://1pwd.org/
    Дата: 12.12.09 22:25
    Оценка:
    Здравствуйте, tyomitch-cs, Вы писали:

    TC>Здравствуйте.


    TC>У меня есть, к примеру:


    TC>
    TC>struct A { float w; int x; } ;
    TC>struct B { char y; A z; } ;
    TC>int B::* p;
    TC>B b;
    TC>


    TC>Как мне теперь в переменную p запихнуть адрес поля B::z.x?

    TC>Так, чтобы b.*p было эквивалентно b.z.x
    TC>Если, по логике вещей, указатель на член -- это просто смещение от начала структуры, то это должно быть возможно, разве нет?


    template <typename T1, typename T2>
    struct super_caster
    {
        union result
        {
            T1 var1;
            T2 var2;
        };
    };
    super_caster<int B::*, size_t> sc;
    sc.result::var2 = offsetof(B2,z)+offsetof(A2,x);
    int B::* p = sc.result::var1;

    ~~~~~
    ~lol~~
    ~~~ Single Password Solution
    Re[2]: указатель на под-член
    От: Caracrist https://1pwd.org/
    Дата: 13.12.09 05:51
    Оценка:
    Здравствуйте, Caracrist, Вы писали:

    C>Здравствуйте, tyomitch-cs, Вы писали:


    TC>>Здравствуйте.


    TC>>У меня есть, к примеру:


    TC>>
    TC>>struct A { float w; int x; } ;
    TC>>struct B { char y; A z; } ;
    TC>>int B::* p;
    TC>>B b;
    TC>>


    TC>>Как мне теперь в переменную p запихнуть адрес поля B::z.x?

    TC>>Так, чтобы b.*p было эквивалентно b.z.x
    TC>>Если, по логике вещей, указатель на член -- это просто смещение от начала структуры, то это должно быть возможно, разве нет?


    C>
    C>template <typename T1, typename T2>
    C>struct super_caster
    C>{
    C>    union result
    C>    {
    C>        T1 var1;
    C>        T2 var2;
    C>    };
    C>};
    C>super_caster<int B::*, size_t> sc;
    C>sc.result::var2 = offsetof(B2,z)+offsetof(A2,x);
    C>int B::* p = sc.result::var1;
    C>

    C>
    можно даже вот так

    
    template <typename T1, typename T2, int assert>
    struct super_caster;
    template <typename T1, typename T2>
    struct super_caster<T1, T2, 0>
    {
        union result
        {
            T1 var1;
            T2 var2;
        };
    };
    template <typename T1, typename T2>
    void super_cast(const T1 & from, T2 & to)
    {
        super_caster<T1,T2,sizeof(T1) - sizeof(T2)> temp;
        temp.result::var1 = from;
        to = temp.result::var2;
    }
    
    // гдето там...
        int B2::* p;
        super_cast(offsetof(B2,z)+offsetof(A2,x), p);

    ~~~~~
    ~lol~~
    ~~~ Single Password Solution
    Re[3]: указатель на под-член
    От: Caracrist https://1pwd.org/
    Дата: 13.12.09 06:03
    Оценка:
    C>template <typename T1, typename T2, int assert>
    C>struct super_caster;
    C>template <typename T1, typename T2>
    C>struct super_caster<T1, T2, 0>
    C>{
    C> union result
    C> {
    C> T1 var1;
    C> T2 var2;
    C> };
    C>};
    C>template <typename T1, typename T2>
    C>void super_cast(const T1 & from, T2 & to)
    C>{
    C> super_caster<T1,T2,sizeof(T1) — sizeof(T2)> temp;
    C> temp.result::var1 = from;
    C> to = temp.result::var2;
    C>}

    C>// гдето там...

    C> int B2::* p;
    C> super_cast(offsetof(B2,z)+offsetof(A2,x), p);
    C>[/ccode]
    C>

    А вот это уже мне интересно

    template <typename T1, typename T2>
    struct super_caster<T1, T2, 0>
    {
        union result
        {
            T1 var1;
            T2 var2;
        };
        char placeHolder[4]; //Если не добавлять эту строчку, то он выжаёт ошибку при выходе из super_cast
    };



    Run-Time Check Failure #2 — Stack around the variable 'temp' was corrupted.


    VS2008, есть идеи?
    ~~~~~
    ~lol~~
    ~~~ Single Password Solution
    Re[4]: указатель на под-член
    От: Caracrist https://1pwd.org/
    Дата: 13.12.09 06:19
    Оценка:
    template <typename T1, typename T2>
    struct super_caster<T1, T2, 0>
    {
        union result
        {
            T1 var1;
            T2 var2;
        };
        char placeHolder[sizeof(T1)]; 
    };

    Похоже union вообще места не занимает, это не должно быть по большему из типов?
    ~~~~~
    ~lol~~
    ~~~ Single Password Solution
    Re[5]: указатель на под-член
    От: Caracrist https://1pwd.org/
    Дата: 13.12.09 06:27
    Оценка:
    Блин вот я прогнал

    template <typename T1, typename T2, int assert>
    struct super_caster;
    template <typename T1, typename T2>
    struct super_caster<T1, T2, 0>
    {
        union result
        {
            T2 value;
        };
        T1 input;
    };
    template <typename T1, typename T2>
    void super_cast(const T1 & from, T2 & to)
    {
        super_caster<T1,T2,sizeof(T1) - sizeof(T2)> temp = {from};
        to = temp.result::value;
    }

    ~~~~~
    ~lol~~
    ~~~ Single Password Solution
    Re[3]: указатель на под-член
    От: rg45 СССР  
    Дата: 13.12.09 08:10
    Оценка:
    Здравствуйте, tyomitch-cs, Вы писали:

    TC>На данном этапе, меня бы даже устроил совет, как реализовать это через reinterpret_cast, лишь бы заработало.


    R>>Если хочешь получить дельную подсказку, опиши задачу немного более верхнего уровня.


    То, что я сейчас напишу вряд ли можно дельной подсказкой. Более правильное название этому — грязный хак. Но ты сам просил об этом. Итак, решаем задачу в первоначальной постановке, которая она была сделана здесь
    Автор: tyomitch-cs
    Дата: 12.12.09
    .

    Для начала определим обобщенную функцию, которая по двум указателям — на член и на подчлен — возвращает их "суперпозицию", так сказать:
    template<typename T, typename O1, typename O2>
    T O1::* superposition(O2 O1::* mem, T O2::* sub)
    {
      int memValue = reinterpret_cast<int&>(mem);  
      int subValue = reinterpret_cast<int&>(sub);  
      int value = memValue + subValue;
      return reinterpret_cast<T O1::*&>(value);
    }


    Теперь применим "инструмент" к данному тобой примеру:
    #include <iostream>
    
    struct A { float w; int x; };
    struct B { char y; A z; };
    
    int B::* p = superposition(&B::z, &A::x);
    
    int main()
    {
      B b;
      b.*p = 123;
      std::cout << b.z.x << std::endl; //Output: 123
    }


    Надо заметить, что задачу, поставленную тобой здесь
    Автор: tyomitch-cs
    Дата: 13.12.09
    , решить будет сложнее, если вообще получится. Проблема в том, что трюки с реинтерпретацией указателей на члены здесь нужно будет проделать над константами времени компиляции. Как это сделать я пока еще не придумал. Склоняюсь к мысли, что это невозможно.
    --
    Справедливость выше закона. А человечность выше справедливости.
    Re[4]: указатель на под-член
    От: rg45 СССР  
    Дата: 13.12.09 08:36
    Оценка:
    Здравствуйте, rg45, Вы писали:

    R>Для начала определим обобщенную функцию, которая по двум указателям — на член и на подчлен — возвращает их "суперпозицию", так сказать:

    R>
    R>template<typename T, typename O1, typename O2>
    R>T O1::* superposition(O2 O1::* mem, T O2::* sub);
    R>


    С помощью этой штуки можно "нырять" на любую глубину:
    struct V { int value; };
    struct W { V v; };
    struct X { W w; };
    struct Y { X x; };
    struct Z { Y y; };
    
    int Z::* imem = superposition(superposition(superposition(superposition(&Z::y, &Y::x), &X::w), &W::v), &V::value);
    --
    Справедливость выше закона. А человечность выше справедливости.
    Re[2]: указатель на под-член
    От: Pavel Dvorkin Россия  
    Дата: 16.12.09 13:49
    Оценка:
    Здравствуйте, tyomitch, Вы писали:

    T>Коллеги, возник ещё один вопрос по теме.

    T>Как сделать указатель на "невидимый член" базового класса?
    T>К примеру:

    T>
    T>struct A { float w; int x; } ;
    T>struct B { char y; } ;
    T>struct C : public A, public B { } ;
    T>B C::* p;
    T>C c;
    T>


    T>И цель — чтобы c.*p было эквивалентно (B)c


    T>Опять же, кажется, что можно изхитриться и узнать смещение предка в потомке, а по нему сконструировать указатель?


    Можно, конечно. Я специально слегка усложнил — переставил местами родителей


    #include "stdafx.h"
    #include "stddef.h"
    
    struct A { float w; int x; } ;
    struct B { char y; } ;
    struct C : public B, public A { } ;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        // хочу доступ к C::A::x
    
        C c;
        B* pB = (B*)&c;
        A* pA = (A*)&c;
        int offsetAinC = (char*) pA - (char*) pB; // а вот в этом быть уверенным я не могу ИМХО. Или могу ? Знатоки стандарта, ответьте!
        int mem = offsetAinC + offsetof(A,x) ;
        int C::* p = (int C::*&) mem;
        c.*p = 123;
        return 0;
    }


    Но вообще — безобразие все это. Грязный хак, вполне согласен с rg45.
    With best regards
    Pavel Dvorkin
    Re[5]: указатель на под-член
    От: XuMuK Россия  
    Дата: 16.12.09 14:50
    Оценка:
    Здравствуйте, Pavel Dvorkin, Вы писали:

    PD>
    PD>int mem = offsetof(B,z) + offsetof(A,x);
    PD>


    http://cplusplus.com/reference/clibrary/cstddef/offsetof/ :

    Because of the extended functionality of structs in C++, in this language, the use of offsetof is restricted to "POD types", which for classes, more or less corresponds to the C concept of struct (although non-derived classes with only public non-virtual member functions and with no constructor and/or destructor would also qualify as POD).

    Re[6]: указатель на под-член
    От: Pavel Dvorkin Россия  
    Дата: 17.12.09 06:19
    Оценка:
    Здравствуйте, XuMuK, Вы писали:

    XMK>Здравствуйте, Pavel Dvorkin, Вы писали:


    PD>>
    PD>>int mem = offsetof(B,z) + offsetof(A,x);
    PD>>


    XMK>http://cplusplus.com/reference/clibrary/cstddef/offsetof/ :

    XMK>

    XMK>Because of the extended functionality of structs in C++, in this language, the use of offsetof is restricted to "POD types", which for classes, more or less corresponds to the C concept of struct (although non-derived classes with only public non-virtual member functions and with no constructor and/or destructor would also qualify as POD).


    Это само собой подразумевалось, что речь идет о структурах С, а не о классах с виртуальностями и т.д.
    With best regards
    Pavel Dvorkin
    Re[3]: указатель на под-член
    От: tyomitch  
    Дата: 17.12.09 13:23
    Оценка:
    Здравствуйте, Pavel Dvorkin, Вы писали:

    PD>Можно, конечно. Я специально слегка усложнил — переставил местами родителей


    PD>
    PD>#include "stdafx.h"
    PD>#include "stddef.h"
    
    PD>struct A { float w; int x; } ;
    PD>struct B { char y; } ;
    PD>struct C : public B, public A { } ;
    
    PD>int _tmain(int argc, _TCHAR* argv[])
    PD>{
    PD>    // хочу доступ к C::A::x
    
    PD>    C c;
    PD>    B* pB = (B*)&c;
    PD>    A* pA = (A*)&c;
    PD>    int offsetAinC = (char*) pA - (char*) pB; // а вот в этом быть уверенным я не могу ИМХО. Или могу ? Знатоки стандарта, ответьте!
    PD>    int mem = offsetAinC + offsetof(A,x) ;
    PD>    int C::* p = (int C::*&) mem;
    PD>    c.*p = 123;
    PD>    return 0;
    PD>}
    
    PD>


    PD>Но вообще — безобразие все это. Грязный хак, вполне согласен с rg45.


    Не совсем то, что я имел в виду (мне нужен был C::A, а не C::A::x), но идея понятна.

    Кстати, в gcc (и вроде бы стандартом тоже) запрещены касты из int в (int C::*&); ради такого преобразования предыдущим отписавшимся в треде и пришлось городить чёрти-что из шаблонов и юнионов.

    Спасибо.
    Re[4]: указатель на под-член
    От: Caracrist https://1pwd.org/
    Дата: 17.12.09 14:20
    Оценка:
    Здравствуйте, tyomitch, Вы писали:


    T>Кстати, в gcc (и вроде бы стандартом тоже) запрещены касты из int в (int C::*&); ради такого преобразования предыдущим отписавшимся в треде и пришлось городить чёрти-что из шаблонов и юнионов.


    И правильно! Я как и все остальные тут создавал UB кастя в int и size_t
    Использовать можно только intptr_t или ptrdiff_t,
    иначе:
    int mem = offsetAinC + offsetof(A,x) ;
    int C::* p = (int C::*&) mem

    на 64 битных указателях, захватит несколько неожиданный кусочек памяти...
    ~~~~~
    ~lol~~
    ~~~ Single Password Solution
    Re[4]: указатель на под-член
    От: Pavel Dvorkin Россия  
    Дата: 18.12.09 03:41
    Оценка:
    Здравствуйте, tyomitch, Вы писали:

    Мне одно не совсем ясно. Зачем тебе это нужно ? Какая польза от того, что ты можешь написать

    C.*p = чему-то ?

    Сделать так, чтобы p мог показывать сейчас на одно, а потом на другое ? Так не проще ли завести вместо этой структуры массив из этих "одно и другое" (они же одного типа!)и добираться через банальный char* ? Как-то я плохо себе представляю ситуацию, когда надо ходить по структуре, показывая на разные по смыслу поля с помощью одного указателя... Я понимаю — указатель на функцию-член, но на данные ?
    Ну уж и не говорю о том. что как только в этой структуре появится что-то виртуальное, так сразу все это накроется медным тазом. Да и вопросы переносимости под сомнением. И из того, что это работает под VC++, не следует, что это вполне соответствует страндарту — на этот вопрос, кстати. так никто и не ответил.
    With best regards
    Pavel Dvorkin
    Re[8]: указатель на под-член
    От: Pavel Dvorkin Россия  
    Дата: 18.12.09 07:52
    Оценка:
    Здравствуйте, Erop, Вы писали:

    PD>>Тем более, что твоя superposition будет, конечно, вынесена в хедер, а хедеры никто не смотрит.

    E>Выделенный тезис представляется мне более чем сомнительным...

    Когда ты последний раз заглядывал в stdio.h ?

    PD>>В итоге... если что-то потом окажется не так, придется разбираться намного дольше. У меня же все ясно и недвусмысленно сказано.


    E>Фишка вы том, что

    E>1) в superposition можно организовать, вообще-то контроль типов.
    E>2) можно организовать тестирование работоспособности этого хака, чтобы на платформе, где всё сломается, сразу и не собралось бы или не запустилось и т. д.
    E>3) (на самом деле главное), когда понадобится переносить этот код на платформу, где хак будет немного другой (например, будут хранить в указателе на поле не смещение, а смещение + константа), то в варианте с superposition понадобится сделать условную компиляцию в одном месте, а у тебя всюду в клиентском коде. И объём правок, конечно разный.

    В общем, со многим можно согласиться, но лучше вообще это нигде не писать и не провоцировать, делая вид, что superposition — это честная функция, а не злобный хак
    With best regards
    Pavel Dvorkin
    Re[2]: указатель на под-член
    От: rg45 СССР  
    Дата: 18.12.09 11:20
    Оценка:
    Здравствуйте, tyomitch, Вы писали:

    T>Коллеги, возник ещё один вопрос по теме.

    T>Как сделать указатель на "невидимый член" базового класса?
    T>К примеру:

    T>
    T>struct A { float w; int x; } ;
    T>struct B { char y; } ;
    T>struct C : public A, public B { } ;
    T>B C::* p;
    T>C c;
    T>


    T>И цель — чтобы c.*p было эквивалентно (B)c


    T>Опять же, кажется, что можно изхитриться и узнать смещение предка в потомке, а по нему сконструировать указатель?


    Ну и я отмечусь:
    template<typename Base, typename Derived>
    Base Derived::* reinterpret_base_as_member()
    {
      int derived_ = 123; //Что угодно, но не 0!
      Derived* derived = reinterpret_cast<Derived*&>(derived_);
      Base* base = derived;
      int base_ = reinterpret_cast<int&>(base);
      int offset = base_ - derived_;
      Base Derived::* member = reinterpret_cast<Base Derived::*&>(offset);
      return member;
    }


    Использовать так:

    #include <iostream>
    
    struct A { int a; };
    struct B { int b; };
    struct AB : A, B { };
    
    B AB::* m = reinterpret_base_as_member<B, AB>();
    
    int main()
    {
      AB t;
      (t.*m).b = 123;
      
      std::cout << t.b << std::endl; //Output: 123
    }


    Хочется обратить внимание на присутствие контроля типов. Если попытаться вызвать reinterpret_base_as_member для типов, не являющихся предком и потомком, то будет ошибка компиляции. Также контроль типов присутствует и здесь
    Автор: rg45
    Дата: 13.12.09
    .
    --
    Справедливость выше закона. А человечность выше справедливости.
    Re[5]: указатель на под-член
    От: rg45 СССР  
    Дата: 18.12.09 16:32
    Оценка:
    Здравствуйте, Кодт, Вы писали:

    К>
    К>// суперпозиция во время компиляции
    К>template<class A, class B, class C, B&(*a2b)(A&), C&(*b2c)(B&)>
    К>C& superposition(A& a) { return b2c(a2b(a)); }
    
    К>int& (*get_x)(Q&) = superposition<Q,P,int, member<Q,P,&Q::z>, member<P,int,&P::x> >;
    К>


    Да, в этом месте очень не хватает автоматического выведения пареметров шаблонной функции по параметрам же шаблона. Наподобие того, как параметры шаблона выводятся из параметров функции.

    Казалось бы, чего бы не перенести указатели на функции из списка параметров шаблона в список параметров функции? А тут есть один тонкий момент, который не всеми сходу улавливается. А между тем, разница в возможностях использования указателей на функции, находящихся в списке параметров шаблона, и указателей в списке параметров функции огромная. Пока указатель на функцию находится в параметрах шаблона он является константой времени компиляции, и на его основе можно определить другую функцию и получить указатель другого типа, и тоже во время компиляции! Таким образом, получается эдакий механизм конвертации указателей на функции. При переносе указателя на функцию из параметров шаблона в параметры функции эта замечательная возможность теряется.

    Лет пять назад я делал приспособление, которое долгое время было предметом моей гордости. Оно позволяло перенести-таки указатели на функции из параметров шаблона в параметры функции, и при этом не потерять описанные выше преимущества! При этом вызовы функций, подобных superposition обходились без этих огромных списков шаблонных параметров и стали выглядеть гораздо компактнее, а самое главное, перестали быть чувствительны к изменениям в сигнатурах целевых функций! В основе решения лежал грязнейший хак, гораздо более грязный, чем все вместе взятые, мелькавшие в этой ветке. В двух словах — из сегмента кода вырезались кусочки исполняемого кода и переносились в буфер, расположенный в динамической памяти. Потом еще выполнялась кое-какая дополнительная инициализация этих блочков. После этого этим кусочкам кода в нужный момент передавалось управление. Собственно, эти кусочки и выполняли роль тех самых функций, которые в первом случае можно было генерить совершенно штатным образом. Решение (на MSVC-7.1) было непереносимым, заточенным под 32-битную платформу. Но оно работало и на тот момент все остались чрезвычайно довольны
    --
    Справедливость выше закона. А человечность выше справедливости.
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.