Ну это ты уже пытаешься увести обсуждение в сторону. Ты название темы-то прочитай.
В этой теме не обсуждается удобен или не удобен для использования в шаблонах. Обсуждается, как обойти накладываемые им ограничения и не влететь на UB. Ты же заменяешь одно UB на другое и обосновываешь это тем, что это удобнее для использования в шаблонах
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
_>>Приведите пример где этот offset_of даёт неверный резульат. Тогда и поговорим.
R>Так ты сам уже привёл этот пример. То, что его результат совпадает с твоими ожиданиями, является лишь частным проявлением неопределённого поведения.
Я про то что если нет виртуальных наследований то всё ок.
struct A { int a; };
struct B : virtual A { int b; };
int main(int argc, char const *argv[]) {
B b[1];
int A:: *p1=&B::a; // + member reference
// int B:: *p2=&B::a; // - virtual memeber reference (очередное c++ и3#$6$тво)int B:: *p3=&B::b; // + member referencereturn 0;
}
Здравствуйте, rg45, Вы писали:
R>Ну, если UB для тебя это всё ОК, то желаю удачи.
Для меня UB это приемлемо, если всё работает как задумано. Проблема в современных компиляторах, для них UB это возможность сделать пакость, причем желательно неочевидную.
R>Только вот здесь
мы как раз обсуждали варианты, как обойти UB. Так что немного не в тему ты вклинился.
Ничего не понял но очень интересно. В c++ нет единообразия везде костыли и подпорки, поэтому имеем то что имеем.
Здравствуйте, kov_serg, Вы писали:
_>Для меня UB это приемлемо, если всё работает как задумано. Проблема в современных компиляторах, для них UB это возможность сделать пакость, причем желательно неочевидную.
Причем, обо всех "пакостях" тебя предупреждают заранее. Но ты считаешь для себя приемлемым игнорировать эти предупреждения. Ну так и кто тебе злобный Буратино.
R>>Только вот здесь
R>Какие именно слова вызыают затруднения с пониманием?
те что из букв
_>>В c++ нет единообразия везде костыли и подпорки, поэтому имеем то что имеем. R>И это закономерный итог — имеете то, что имеете.
Да
#include <iostream>
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual A { int c; };
struct D : B,C { int d; };
template<class T> T* get_instance() { static T t[1]; return t; }
template<class T,auto m> size_t offset() {
T *t=get_instance<T>(); return (char*)&(t->*m)-(char*)t;
}
int main(int argc,char **argv) {
std::cout<< "b:" << offset<D,&D::b>() << std::endl;
std::cout<< "c:" << offset<D,&D::c>() << std::endl;
std::cout<< "d:" << offset<D,&D::d>() << std::endl;
std::cout<< "a:" << offset<D,&D::a>() << std::endl;
return 0;
}
_>#include <iostream>
_>struct A { int a; };
_>struct B : virtual A { int b; };
_>struct C : virtual A { int c; };
_>struct D : B,C { int d; };
_>template<class T> T* get_instance() { static T t[1]; return t; }
_>template<class T,auto m> size_t offset() {
_> T *t=get_instance<T>(); return (char*)&(t->*m)-(char*)t;
_>}
_>int main(int argc,char **argv) {
_> std::cout<< "b:" << offset<D,&D::b>() << std::endl;
_> std::cout<< "c:" << offset<D,&D::c>() << std::endl;
_> std::cout<< "d:" << offset<D,&D::d>() << std::endl;
_> std::cout<< "a:" << offset<D,&D::a>() << std::endl;
_> return 0;
_>}
_>
Ну вот, без UB, но компайл тайм сразу пошёл погулять лесом. И для классов без дефолтных конструкторов это уже не работает. И для "тяжёлых" классов применять это уже стрёмно. А вдруг, класс в дефолтном конструкторе нажимает на кнопку уничтожения Вселенной?
И что ты хочешь продемонстрировать этим примером?
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Здравствуйте, kov_serg, Вы писали:
_>>
_>>#include <iostream>
_>>struct A { int a; };
_>>struct B : virtual A { int b; };
_>>struct C : virtual A { int c; };
_>>struct D : B,C { int d; };
_>>template<class T> T* get_instance() { static T t[1]; return t; }
_>>template<class T,auto m> size_t offset() {
_>> T *t=get_instance<T>(); return (char*)&(t->*m)-(char*)t;
_>>}
_>>int main(int argc,char **argv) {
_>> std::cout<< "b:" << offset<D,&D::b>() << std::endl;
_>> std::cout<< "c:" << offset<D,&D::c>() << std::endl;
_>> std::cout<< "d:" << offset<D,&D::d>() << std::endl;
_>> std::cout<< "a:" << offset<D,&D::a>() << std::endl;
_>> return 0;
_>>}
_>>
R>Ну вот, без UB, но компайл тайм сразу пошёл погулять лесом. И для классов без дефолтных конструкторов это уже не работает. И для "тяжёлых" классов применять это уже стрёмно. А вдруг, класс в дефолтном конструкторе нажимает на кнопку уничтожения Вселенной?
R>И что ты хочешь продемонстрировать этим примером?
То что в C++ нет указателя &D::a вместо используется &A::a. Вот нахрена так было делать?
Здравствуйте, kov_serg, Вы писали:
_>Здравствуйте, rg45, Вы писали:
R>>Здравствуйте, kov_serg, Вы писали:
_>>>
_>>>#include <iostream>
_>>>struct A { int a; };
_>>>struct B : virtual A { int b; };
_>>>struct C : virtual A { int c; };
_>>>struct D : B,C { int d; };
_>>>template<class T> T* get_instance() { static T t[1]; return t; }
_>>>template<class T,auto m> size_t offset() {
_>>> T *t=get_instance<T>(); return (char*)&(t->*m)-(char*)t;
_>>>}
_>>>int main(int argc,char **argv) {
_>>> std::cout<< "b:" << offset<D,&D::b>() << std::endl;
_>>> std::cout<< "c:" << offset<D,&D::c>() << std::endl;
_>>> std::cout<< "d:" << offset<D,&D::d>() << std::endl;
_>>> std::cout<< "a:" << offset<D,&D::a>() << std::endl;
_>>> return 0;
_>>>}
_>>>
R>>И что ты хочешь продемонстрировать этим примером? _>То что в C++ нет указателя &D::a вместо используется &A::a. Вот нахрена так было делать?
Ну потому что поле "a" является членом класса A. И выражение &D::a имеет тип указателя на член класса А. И указатель на член класса A без проблем может быть использован с объектом класса D, как с наследником класса A. А почему должно быть по-другому?
И вообще, какую связь ты видишь между этими вопросами и данной темой?
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Ну потому что поле "a" является членом класса A. И выражение &D::a имеет тип указателя на член класса А. И указатель на член класса A без проблем может быть использован с объектом класса D, как с наследником класса A. А почему должно быть по-другому?
Согласен, в c++ если можно сделать через ж... не единообразно то делают именно так.
R>И вообще, какую связь ты видишь между этими вопросами и данной темой?
Можно заранее (precompile) заготовить смещений вот где... зато будет constexpr.
Здравствуйте, kov_serg, Вы писали:
_>Согласен, в c++ если можно сделать через ж... не единообразно то делают именно так.
Пора уже отдельный форум создавать — "сердитых на С++". Модераторы быстро найдутся, я думаю.
R>>И вообще, какую связь ты видишь между этими вопросами и данной темой? _>Можно заранее (precompile) заготовить смещений вот где... зато будет constexpr.
Ну это уже чтоб точно "через ж..."
--
Справедливость выше закона. А человечность выше справедливости.
_>struct A { int a; };
_>struct B : virtual A { int b; };
_>struct C : virtual A { int c; };
_>struct D : B,C { int d; };
_>
R>>Ну потому что поле "a" является членом класса A. И выражение &D::a имеет тип указателя на член класса А. И указатель на член класса A без проблем может быть использован с объектом класса D, как с наследником класса A. А почему должно быть по-другому?
_>Согласен, в c++ если можно сделать через ж... не единообразно то делают именно так.
Давай порассуждаем?
Легально ли такое использование, или его следует запретить?
D d{};
auto m = &A::a;
std::cout << d.*m << std::endl;
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
R>Давай порассуждаем? R>Легально ли такое использование, или его следует запретить?
R>
R> D d{};
R> auto m = &A::a;
R> std::cout << d.*m << std::endl;
R>
Уже позно запрещать. Не нужно было вводить указатели на неведомую фигню.
У вас есть указатель на typedef? Тут примерно тоже самое. Сами себе создали проблемы и потом в лучщих традициях: породили новую сущность, породили методы работы с ней, но они не стыкуются с уже имеющимися,а и так сойдет.
struct A { int x[2]; };
struct B { A a[2]; };
Вот как записать указатель на поле B::a[1].x[1]. Обычного смещения относительно B было бы достаточно.
struct A { int *x; };
struct B { A *a; };
А вот для такого указателя на поле B::a[1].x[1]. Уже было бы достаточно ввести метод получения адреса, собственно и указатель бы был указателем на этот метод. Но нет это слишком просто.
R>> D d{};
R>> auto m = &A::a;
R>> std::cout << d.*m << std::endl;
R>>
_>Уже позно запрещать. Не нужно было вводить указатели на неведомую фигню. _>У вас есть указатель на typedef? Тут примерно тоже самое. Сами себе создали проблемы и потом в лучщих традициях: породили новую сущность, породили методы работы с ней, но они не стыкуются с уже имеющимися,а и так сойдет.
Чё-то эмоции через край, а на вопрос так и не ответил. Допустимо такое использование указателя на член, или нет? С твоей точки зрения, разумеется. Желательно с обоснованием.
--
Справедливость выше закона. А человечность выше справедливости.
R>>> D d{};
R>>> auto m = &A::a;
R>>> std::cout << d.*m << std::endl;
R>>>
_>>Уже позно запрещать. Не нужно было вводить указатели на неведомую фигню. _>>У вас есть указатель на typedef? Тут примерно тоже самое. Сами себе создали проблемы и потом в лучщих традициях: породили новую сущность, породили методы работы с ней, но они не стыкуются с уже имеющимися,а и так сойдет.
R>Чё-то эмоции через край, а на вопрос так и не ответил. Допустимо такое использование указателя на член, или нет? С твоей точки зрения, разумеется. Желательно с обоснованием.
Да допустимо. При условии что тип d приводится к A а потом применяется указатель на поле класса A.
Здравствуйте, kov_serg, Вы писали:
R>>Чё-то эмоции через край, а на вопрос так и не ответил. Допустимо такое использование указателя на член, или нет? С твоей точки зрения, разумеется. Желательно с обоснованием.
_>Да допустимо. При условии что тип d приводится к A а потом применяется указатель на поле класса A.
Не получается у меня что-то цепочка рассуждений, которая могла бы тебя переубедить. Я ещё подумаю.
--
Справедливость выше закона. А человечность выше справедливости.
Здравствуйте, rg45, Вы писали:
_>>Да допустимо. При условии что тип d приводится к A а потом применяется указатель на поле класса A. R>Не получается у меня что-то цепочка рассуждений, которая могла бы тебя переубедить. Я ещё подумаю.
Здравствуйте, kov_serg, Вы писали:
_>Пока думаешь. Я говорю примерно про такое
Да идею-то я понял. Я не понимаю, каким образом тебе мешает то, что выражение &D::a имеет тип int A::*. Что для тебя изменилось бы, если бы тип был int D:*?
--
Справедливость выше закона. А человечность выше справедливости.