Наверное, нет, потому что void — неинстанциируемый тип, и поэтому это должно быть невалидно даже в decltype-контексте.
А вы разве его инстанцируете?
Но я не уверен, конечно
Вот это уже — больше похоже на правду.
Вы только что утверждали, что сломается очень много шаблонного кода, который опирается на неполноту void.
Да, сломается.
Это в том числе такой код
Нет, не такой.
(и кроме (не)возможности инстанциировать неполный тип с очевидными оговорками про параметры конструктора и невозможности применить sizeof к самому void я не могу придумать вообще ничего).
Ничего особо мудрёного придумывать и не требуется.
Требуется грамотно реализовать.
Теперь вы пишете, что это очень редкий случай.
Да, редкий.
Вам не кажется, что в таком варианте вашего кода clang вдруг почему-то резко "починился" и стал работать правильно?
Правильно в данном случае это — так, как я говорю, а не как вы ожидаете.
Или скажете, что теперь и clang сломан, раз вы ожидаете от него другого поведения?
Можно как-то определиться, если не сложно?
Это не мне следует определиться, а вам понимание своё на новый уровень поднять.
Вы неправильно реализовали свой пример, у вас там нет инстанцирования.
Чтобы оно было, его следует доработать, например, так.
Видите, теперь и gcc работает так, как вы задумывали.
Или, если максимально близко к вашему варианту, а также используя невозможность ссылок на void, так.
И опять gcc "заработал правильно".
Какая проблема? Он как раз правильно работает в данном случае.
Вы не поняли сути происходящего, не поняли, почему clang в данном случае так работает.
Я вам предлагал увидеть такую же работу и других компиляторов, путём отматывания их версий на более древние.
То есть, в других компиляторах эту ошибку со временем исправили, неисправленным остался только clang.
Поэтому, процитировав ещё раз:
Ох лол, я сконструировал такой пример, но там gcc и clang показывают разные результаты, что в очередной раз намекает нам, что плюсы безнадёжно сломаны
повторю: сломаны были компиляторы, а не плюсы.
Сейчас почти все компиляторы починены, кроме clang'а.
А вот что в этой ситуации "лол", так это — отнюдь, не компиляторы и, тем более, не C++.
Это аналог запрета деления на 0. Никто ж не говорит, что он рушит арифметику. Наоборот, он позволяет объяснить, почему нельзя обратить умножение на 0. Тут же запрет будет ограничивать итерации по коллекциям элементов 0-го размера через указатели.
Это — не эквивалентные вещи.
При делении на 0 не получается представить результат. И запрета на деление на 0 — нет, это — UB, а не "запрет".
А при прибавлении 0 к указателю результат — представим. И никакого UB там не возникает.
Можно ли пример, у которого есть шанс встретиться в реальном коде?
Чем этот пример не реален?
А то как будто специально сначала расставляем грабли с одноимённым foo в разных контекстах, потом на них наступаем.
Вы говорили:
Сходу не могу придумать пример. Подскажете?
Я привёл вам пример, из которого видна суть, а теперь вы привередничаете.
В реальном коде будет эксплуатироваться та же самая суть.
раньше возвращал 0, а будет возвращать 1. Изменение? Но корректное!
Какое бы оно ни было, корректное или нет, но оно приведёт к тому, что старый код начнёт работать по-другому.
Я могу сказать, что ваш пример из той же серии, просто обфусцированный. То есть, изменение полностью корректное и ничего не ломает.
В старом коде начнут вызываться не те функции — это ничего не ломает?
Адресная арифметика работает с void*? Если не работает, то как это «никакого запрета нет»?
А вот так: условия не соблюдены.
Представьте себе, что завтра в стандарт добавят отдельную явную фразу «адресная арифметика с void* запрещена». Сломает ли это хоть какой-то существующий код?
Нет. И это косвенно говорит о том, что сейчас запрета нет.
Стандарт вам уже прямо сейчас указывает так не делать. Будет указывать дальше, в чём вопрос?
Я же — о случаях, когда Стандарт разрешает.
А она действительно неважна постольку, поскольку наблюдаемое поведение компилятора такое же.
Об этом — ниже.
Окей, напишите программу, где работает адресная арифметика с void, раз она нигде не запрещена.
Так условия не соблюдены.
Вы продолжаете утверждать, что причина неважна, и поэтому ходите в этом месте по кругу.
Когда условия теоремы не соблюдены, теорема не применима. Также и с адресной арифметикой: если условия для неё не соблюдены, она — не применима.
Дописали в стандарт фразу «void is a complete type, its size is zero, but pointer arithmetic with void* is prohibited». В чём конкретная проблема с таким решением?
Уже обсуждалось: разные объекты могут иметь как разные адреса, так и одинаковые, а в последнем случае их нельзя отличить.
Тогда уже вводите и несравнимость адресов для void.
Не считаю это меньшей проблемой,
Большинство считает, поэтому и не соглашается на предлагаемые вами изменения в Стандарт.
Стройная модель не нарушается: если хотим, чтобы итерирование по адресам не приводило к непонятным багам, значит запрещаем увеличивать указатель на 0 при итерациях.
Раз что-то там запрещаем для конкретного случая, значит стройная модель нарушается, потому что сейчас всё работает без всяких "подтычек".
Возможный компромис - зафиксировать sizeof(void)==0, но запретить прибавление скаляра к указателю на тип нулевого размера, как следствие, запретить брать разность таких указателей.
То есть, явно запретить адресную арифметику для таких типов, нарушив стройную модель: операция sizeof определена для типа — есть адресная арифметика, не определена — нет.
Шансов у такого предложения будет очень мало.
Если речь обо мне, то вы неверно поняли. Мне нужно, чтобы void был инстанциируемым типом. Размер 0 - просто пожелание, гармонирующее с моим понимаем красоты, но не обязательное требование.
Да, о вас, но понял я правильно.
Раз — пожелание, то вы и согласились на размер 1. А это снимает главную проблему с адресной арифметикой.
Шансов на void, который будет complete-типом с размером 1, невообразимо больше, чем на тот же void с размером 0.
Но я боюсь, что уже имеется очень много шаблонного кода, который опирается на то, что void — incomplete-тип (не инстанцируемый), и этот код сломается, если void сделать complete-типом, поэтому шансов даже у такого варианта — нет.
Она де-факто запрещена сейчас для void* , почему — неважно.
Никакого запрета нет. Очень важно, почему.
Адресная арифметика не работает не только с void:
struct s;
void fun0(s *p, size_t const n) {
for (s const *const end{p + n}; p < end; ++p) {
*p = {};
}
}
struct s {
};
void fun1(s *p, size_t const n) {
for (s const *const end{p + n}; p < end; ++p) {
*p = {};
}
}
Сообщение об ошибке, но исключительно для функции fun0:
source>:7:28: error: arithmetic on a pointer to an incomplete type 's' 7 | for (s const *const end{p + n}; p < end; ++p) {
Как только размер типа становится известен, так сразу начинает работать адресная арифметика, причём, вполне определённым образом, поэтому функция fun1 уже может использовать адресную арифметику с типом s.
Но тип-то — тот же самый для обеих функций, их тела — идентичны!
Никаких запретов на адресную арифметику нет, но есть условие, при котором она становится возможна.
Вы не хотите этого замечать, поэтому пытаетесь утверждать, что причина, по которой адресная арифметика не работает для void *, не важна.
Да, it != end, примерно как я и пишу ниже.
Очевидно, что такая проверка не отличает отсутствие элементов от их наличия в массиве объектов с нулевым размером, и это — проблема.
Значит, вы используете ваш массив как счётчик.
Во-первых, это -- далеко не единственный вариант, а, во-вторых, — имею право.
Зачем вы это делаете? Просто передавайте число.
Никто не может указывать программисту, что и как делать в пределах Стандарта. Поэтому вопрос "зачем" — бессмысленный, а указания, как и что программисту делать — неуместны.
При этом текущий void тоже «никуда не годится», потому что метапрограммировать сложно
Это — куда меньшая проблема, и она — одна.
А вот чтобы наткнуться на упомянутые вами проблемы, нужно зачем-то сделать массив voidов и потом на его элементах ещё вызывать функции с сайд-эффектами, чтобы вообще заметить, что там какая-то ерунда с количеством элементов.
Массив не void'ов, а элементов типа T, который может выводиться и как void.
Ну и ещё нужно в очередной раз обделаться с дополнением стандарта языка (чтобы зачем-то разрешить адресную арифметику на voidах, например), но тут сомнений в способностях Комитета у меня нет.
Она нигде и не запрещалась, но условием её работы является наличие возможности получить размер элемента.
При этом есть такие типы, которые — complete, но адресная арифметика для них все равно невозможна, потому что операция sizeof для этих типов не определена.
Опять же, суть здесь — в наличии возможности знать размер элемента, а не в чём-то другом, типа, complete тип или incomplete и так далее, а не в каких-то выдуманных вами запретах.
в плюсах (и в C) невозможно сделать полностью правильный и консистентный язык просто потому, что там уже заложено достаточно противоречий. Поэтому вопрос сводится к тому, с какими из них вы готовы мириться. Мне метапрограммирование представляется более важным, чем особенности итерации по массивам из voidов (которые сейчас вообще запрещены, опять же).
Похоже, у вас много достаточно безапелляционных хотелок, и это очень искажает ваше восприятие вплоть до "запрета" адресной арифметики для void *, которого нет.
Действительно, ведь у void нет других применений, кроме как создавать из него массивы и потом по ним итерироваться.
Код бывает шаблонный, а тип может быть выведен как void.
Но даже если и явный void в качестве элементов массива — вы не можете запретить даже это после того, как станет возможным определить размер типа void.
Весь разговор о метапрограммировании, весь исходный пост — он про что-то другое.
Нет, сейчас разговор не о метапрограммировании, а — о том, что такой способ сделать тип void complete, при котором его размер равен 0, порождает такие проблемы, с которыми смириться нельзя.
Кстати, я бегло перечитал тред, но не заметил ответа на другой вопрос: чем вам не нравится sizeof void = 1?
Очевидно, что такого ответа, чем не нравится, нет.
В качестве такого типа может выступать пустая структура, но человек, согласившийся на размер void'а, равный 1, сказал, что ему нужно, чтобы именно тип void обладал свойствами пустой структуры, заведение своей структуры его не устраивает.
Справедливости ради, часто вопросы "что выведет код" они просто выбешивающие. Потому что дают тебе код который умственно полноценный человек никогда в жизни не напишет.
Не весь код, с которым приходится работать, производит впечатление написанного умственно полноценными, но работать с этим кодом все равно необходимо, то есть, необходимо понимать, что этот код делает.
Я если сразу не могу сказать ответ, то просто отвечаю, что лично у меня такой код не выведет ничего, потому что я ни сам его никогда не напишу, ни кому-либо другому не дам написать, если смогу.
Ваши возможности в этом плане — очень ограничены, вы не сможете избавиться от необходимости работать с таким кодом, потому что он может придти извне.
Обычно вопросы типа "что выведет код" — на глубокое понимание языка.
Покажете шаблонную функцию, где нужно защищаться от присваивания самому себе, особенно в случае с void?
Не смешно.
Нет, она вообще не будет работать (как и сегодня), потому что нулевой размер void не означает, что надо автоматически разрешить адресную арифметику с void*. Но, впрочем…
Её нет необходимости "разрешать", она и так "разрешена" принципиально для любого типа, для которого в текущей точке программы известен его размер.
… даже если бы адресная арифметика с void* была разрешена в предположении a[i] = a[0] ∀i, то это в частности бы означало, что указатель на начало массива совпадал бы с указателем на его конец
Что означает отсутствие элементов. Типичное условие окончания цикла на итераторах видели?
отработал бы ровно ноль раз, потому что pos = start = end.
А должен отработать столько раз, сколько элементов в массиве.
Что, кстати, более чем согласно с теорией, потому что элементы массива voidов неразличимы, поэтому можно делать ноль итераций: никакой новой информации от какого бы то ни было элемента вы не узнаете.
А если в теле цикла вызов функции с побочным эффектом?
Вот здесь, благодаря наличию подходящих расширений в компиляторах, я показываю, что один цикл, работающий через адресную арифметику, не отработает ни для одного элемента, а другой, по индексам массива, отработает, как положено, для каждого элемента.
Очевидно, что такое введение "обновлённого" типа void в язык никуда не годится.
Как красиво, когда теория достаточно консистентна, чтобы приводить ко вполне ожидаемым результатам даже в, казалось бы, весьма крайних случаях, не правда ли?
В первую очередь важна правильность, а не красота.
Если один вид цикла по массиву приводит к итерациям по всем элементам, а другой — "делает вид", что элементов нет, то зачем нужен такой void?
Мы обсуждаем void, там, во-первых, это присваивание мы не пишем руками, а, во-вторых, у него нет рантайм-поведения, потому что тип void пустой, поэтому и защищаться от него не надо: всё равно скомпилируется в nop.
Функции бывают шаблонными.
Ни одна из этих причин не применима к void просто потому, что все объекты этого типа одинаковые по определению, и различать их необходимости нет.
Хорошо, шаблонная функция в давно написанном коде, которая выполняет итерации надо массивом с помощью явных указателей, а не итераторов, будет работать неправильно для типа void с нулевым размером.
Упрощает метапрограммирование. Можете, например, перечитать пост, под которым мы тут комментарии пишем.
Но вносит неустранимые проблемы, указанные мной выше.
А что мы теряем? Сейчас невозможно было создать контейнер с элементами нулевого размера. С новой фичей можно, но нужно быть осторожнее с итерациями. То есть, появляется новая возможность, старое ничего не ломается.
6 часов назад вы согласились на ненулевой размер. Согласились именно потому, что старое ломается.
Указатели — не итераторы, хотя и могут быть использованы, как таковые.
Хорошо. Я согласен на sizeof(void)==1, но доступ к этому значению - no-op, и поэтому компилятор вправе не занимать регистр при отпимизации ф-ций с типом void.
Так это так и происходит с типом boid, описанным в статье.
Напишите функцию, в которую передаются объекты типа boid, в функции присваиваются один другому и возвращается какой-нибудь из них, например, которому присвоили.
Посмотрите, какой получается ассемблерный код. Там будет всегда одна инструкция ret.
Я думаю, что аргумент против изменения поведения типа void будет именно такой, что то, что вы хотите, эмулируется пустой структурой с соответствующими конструкторами, операторами "равно" и деструктором.
Я потерял нить диалога. Сначала вы доказываете, что void - объект
Не в том смысле, что это — класс, а в смысле -- некий intance.
А теперь уже и this упоминаете. Какой this в операциях с простыми типами?
Нет, речь о том, что вызов метода — синтаксический сахар.
#include <cstdlib>
#include <functional>
#include <iostream>
void f(int n, int m) {
std::cout << __func__ << ", n: " << n << ", m: " << m << std::endl;
}
struct S {
void m(int n) {
std::cout << __func__ << ", this: " << this << ", n: " << n << std::endl;
}
} s;
int main() {
std::invoke(f, 1, 2);
std::invoke(&S::m, s, 3);
return EXIT_SUCCESS;
}
Видите, в обоих случаях у std::invoke — по 3 параметра. Но у метода здесь — один параметр, а у функции — два.
Потому что у метода, на самом деле, — тоже два параметра в силу того, что у него есть ещё неявный параметр this, несмотря на то, что он отсутствует в синтаксисе как параметр.
Поэтому нет принципиальной разницы между вызовом метода у объекта класса и вызовом функции, которой передан явный адрес/ссылка на некий instance.
тут пишут, что это всё-таки нарушение Стандарта компилятором
Это не может быть нарушением Стандарта.
Как только компилятор используется в режиме с расширениями, так он сразу же перестаёт быть компилятором C/C++ и становится компилятором некоторого языка, похожего на C/C++, на который даже стандарта нет.
Вот если бы он так себя вёл в режиме без расширений, тогда — да, было бы нарушение Стандарта.
А вы разве его инстанцируете?
Вот это уже — больше похоже на правду.
Да, сломается.
Нет, не такой.
Ничего особо мудрёного придумывать и не требуется.
Требуется грамотно реализовать.
Да, редкий.
Вам не кажется, что в таком варианте вашего кода clang вдруг почему-то резко "починился" и стал работать правильно?
Правильно в данном случае это — так, как я говорю, а не как вы ожидаете.
Или скажете, что теперь и clang сломан, раз вы ожидаете от него другого поведения?
Это не мне следует определиться, а вам понимание своё на новый уровень поднять.
Вы неправильно реализовали свой пример, у вас там нет инстанцирования.
Чтобы оно было, его следует доработать, например, так.
Видите, теперь и gcc работает так, как вы задумывали.
Или, если максимально близко к вашему варианту, а также используя невозможность ссылок на
void
, так.И опять gcc "заработал правильно".
Вы не поняли сути происходящего, не поняли, почему clang в данном случае так работает.
Я вам предлагал увидеть такую же работу и других компиляторов, путём отматывания их версий на более древние.
То есть, в других компиляторах эту ошибку со временем исправили, неисправленным остался только clang.
Поэтому, процитировав ещё раз:
повторю: сломаны были компиляторы, а не плюсы.
Сейчас почти все компиляторы починены, кроме clang'а.
А вот что в этой ситуации "лол", так это — отнюдь, не компиляторы и, тем более, не C++.
Это — не эквивалентные вещи.
При делении на 0 не получается представить результат.
И запрета на деление на 0 — нет, это — UB, а не "запрет".
А при прибавлении 0 к указателю результат — представим.
И никакого UB там не возникает.
Чем этот пример не реален?
Вы говорили:
Я привёл вам пример, из которого видна суть, а теперь вы привередничаете.
В реальном коде будет эксплуатироваться та же самая суть.
Какое бы оно ни было, корректное или нет, но оно приведёт к тому, что старый код начнёт работать по-другому.
В старом коде начнут вызываться не те функции — это ничего не ломает?
А вот так: условия не соблюдены.
Нет.
И это косвенно говорит о том, что сейчас запрета нет.
Я же — о случаях, когда Стандарт разрешает.
Об этом — ниже.
Так условия не соблюдены.
Вы продолжаете утверждать, что причина неважна, и поэтому ходите в этом месте по кругу.
Когда условия теоремы не соблюдены, теорема не применима.
Также и с адресной арифметикой: если условия для неё не соблюдены, она — не применима.
Уже обсуждалось: разные объекты могут иметь как разные адреса, так и одинаковые, а в последнем случае их нельзя отличить.
Тогда уже вводите и несравнимость адресов для
void
.Большинство считает, поэтому и не соглашается на предлагаемые вами изменения в Стандарт.
Нет, сломаны компиляторы, а не плюсы.
Если вы поотматываете версии компиляторов в прошлое, то увидите, что проблема была и у gcc, и у MSVC.
А что, разве не должен?
Нет, отмотка версий компиляторов позволяет установить, что проблему постепенно исправляют.
Случай — очень редкий, видимо, поэтому процесс идёт медленно.
На данный момент проблема осталась только у clang'а.
Раз что-то там запрещаем для конкретного случая, значит стройная модель нарушается, потому что сейчас всё работает без всяких "подтычек".
Что-нибудь такое:
В данном случае функции даже определять не требуется.
Когда шаблонная функция
foo
должна вернуть ссылку наvoid
, ищется следующая подходящая перегрузка, и она находится.Если
void
сделать "инстанцируемым", после чего станут возможны ссылки наvoid
, выбираться будет шаблонная функция вместо нешаблонной.Контекст здесь — невычислимый (потому что под
sizeof
'ом), поэтому определять функции не обязательно.Нешаблонная функция
foo
возвращает ссылку на массив из 100char
'ов.Функция
bar
возвращает 104.То есть, явно запретить адресную арифметику для таких типов, нарушив стройную модель: операция
sizeof
определена для типа — есть адресная арифметика, не определена — нет.Шансов у такого предложения будет очень мало.
Да, о вас, но понял я правильно.
Раз — пожелание, то вы и согласились на размер 1.
А это снимает главную проблему с адресной арифметикой.
Шансов на
void
, который будет complete-типом с размером 1, невообразимо больше, чем на тот жеvoid
с размером 0.Но я боюсь, что уже имеется очень много шаблонного кода, который опирается на то, что
void
— incomplete-тип (не инстанцируемый), и этот код сломается, еслиvoid
сделать complete-типом, поэтому шансов даже у такого варианта — нет.Никакого запрета нет.
Очень важно, почему.
Адресная арифметика не работает не только с
void
:Сообщение об ошибке, но исключительно для функции
fun0
:Как только размер типа становится известен, так сразу начинает работать адресная арифметика, причём, вполне определённым образом, поэтому функция
fun1
уже может использовать адресную арифметику с типомs
.Но тип-то — тот же самый для обеих функций, их тела — идентичны!
Никаких запретов на адресную арифметику нет, но есть условие, при котором она становится возможна.
Вы не хотите этого замечать, поэтому пытаетесь утверждать, что причина, по которой адресная арифметика не работает для
void *
, не важна.Очевидно, что такая проверка не отличает отсутствие элементов от их наличия в массиве объектов с нулевым размером, и это — проблема.
Во-первых, это -- далеко не единственный вариант, а, во-вторых, — имею право.
Никто не может указывать программисту, что и как делать в пределах Стандарта. Поэтому вопрос "зачем" — бессмысленный, а указания, как и что программисту делать — неуместны.
Это — куда меньшая проблема, и она — одна.
Массив не
void
'ов, а элементов типаT
, который может выводиться и какvoid
.Она нигде и не запрещалась, но условием её работы является наличие возможности получить размер элемента.
При этом есть такие типы, которые — complete, но адресная арифметика для них все равно невозможна, потому что операция
sizeof
для этих типов не определена.Опять же, суть здесь — в наличии возможности знать размер элемента, а не в чём-то другом, типа, complete тип или incomplete и так далее, а не в каких-то выдуманных вами запретах.
Похоже, у вас много достаточно безапелляционных хотелок, и это очень искажает ваше восприятие вплоть до "запрета" адресной арифметики для
void *
, которого нет.Код бывает шаблонный, а тип может быть выведен как
void
.Но даже если и явный
void
в качестве элементов массива — вы не можете запретить даже это после того, как станет возможным определить размер типаvoid
.Нет, сейчас разговор не о метапрограммировании, а — о том, что такой способ сделать тип
void
complete, при котором его размер равен 0, порождает такие проблемы, с которыми смириться нельзя.Очевидно, что такого ответа, чем не нравится, нет.
В качестве такого типа может выступать пустая структура, но человек, согласившийся на размер
void
'а, равный 1, сказал, что ему нужно, чтобы именно типvoid
обладал свойствами пустой структуры, заведение своей структуры его не устраивает.Не весь код, с которым приходится работать, производит впечатление написанного умственно полноценными, но работать с этим кодом все равно необходимо, то есть, необходимо понимать, что этот код делает.
Ваши возможности в этом плане — очень ограничены, вы не сможете избавиться от необходимости работать с таким кодом, потому что он может придти извне.
Обычно вопросы типа "что выведет код" — на глубокое понимание языка.
Не смешно.
Её нет необходимости "разрешать", она и так "разрешена" принципиально для любого типа, для которого в текущей точке программы известен его размер.
Что означает отсутствие элементов.
Типичное условие окончания цикла на итераторах видели?
А должен отработать столько раз, сколько элементов в массиве.
А если в теле цикла вызов функции с побочным эффектом?
Вот здесь, благодаря наличию подходящих расширений в компиляторах, я показываю, что один цикл, работающий через адресную арифметику, не отработает ни для одного элемента, а другой, по индексам массива, отработает, как положено, для каждого элемента.
Очевидно, что такое введение "обновлённого" типа
void
в язык никуда не годится.В первую очередь важна правильность, а не красота.
Если один вид цикла по массиву приводит к итерациям по всем элементам, а другой — "делает вид", что элементов нет, то зачем нужен такой
void
?Кто ж вам запретит не соглашаться?
Функции бывают шаблонными.
Хорошо, шаблонная функция в давно написанном коде, которая выполняет итерации надо массивом с помощью явных указателей, а не итераторов, будет работать неправильно для типа
void
с нулевым размером.Но вносит неустранимые проблемы, указанные мной выше.
Там ещё и пузырьковая есть.
6 часов назад вы согласились на ненулевой размер.
Согласились именно потому, что старое ломается.
Указатели — не итераторы, хотя и могут быть использованы, как таковые.
Возьмётесь?
Проблема останется, даже если незачем.
А если вместо итераторов в коде явно берётся адрес через
std::addressof
?Уже обсуждали пробег по массиву указателями в уже написанном шаблонном коде.
Так это так и происходит с типом
boid
, описанным в статье.Напишите функцию, в которую передаются объекты типа
boid
, в функции присваиваются один другому и возвращается какой-нибудь из них, например, которому присвоили.Посмотрите, какой получается ассемблерный код.
Там будет всегда одна инструкция
ret
.Я думаю, что аргумент против изменения поведения типа
void
будет именно такой, что то, что вы хотите, эмулируется пустой структурой с соответствующими конструкторами, операторами "равно" и деструктором.По данным — согласен.
Но у instance'ов ещё и адреса есть, их не только по данным, но и по адресам можно различать.
Поэтому передавать в
this
что угодно — нельзя.Да, специализированные итераторы и так далее.
Я даже специально попробовал, чтобы убедиться.
Существующий range-based
for
это не вылечит, но циклы на итераторах работают.Но с уже давно написанным шаблонным кодом проектов и библиотек, который явно использует указатели в качестве итераторов, проблемы останутся.
Думаю, это — вполне аргумент.
Да, это — о качестве кода компилятора gcc, а не об идее.
Не в том смысле, что это — класс, а в смысле -- некий intance.
Нет, речь о том, что вызов метода — синтаксический сахар.
Видите, в обоих случаях у
std::invoke
— по 3 параметра.Но у метода здесь — один параметр, а у функции — два.
Потому что у метода, на самом деле, — тоже два параметра в силу того, что у него есть ещё неявный параметр
this
, несмотря на то, что он отсутствует в синтаксисе как параметр.Поэтому нет принципиальной разницы между вызовом метода у объекта класса и вызовом функции, которой передан явный адрес/ссылка на некий instance.
Это не может быть нарушением Стандарта.
Как только компилятор используется в режиме с расширениями, так он сразу же перестаёт быть компилятором C/C++ и становится компилятором некоторого языка, похожего на C/C++, на который даже стандарта нет.
Вот если бы он так себя вёл в режиме без расширений, тогда — да, было бы нарушение Стандарта.