У типобезопасности и метапрограммных трюков есть некоторая цена, как минимум в эталонной реализации от NVIDIA -- template instantiation stack почти переполняется даже при компиляции hello_world-а. Боюсь себе представить что будет, когда и если этим начнут пользоваться в реальном мире.
Разумеется, это совершенная ерунда. По открытым данным в 2021-м году в JetBrains работало 1900+ человек из них 1500+ в российских офисах. Если почти всех их уволить, продолжать разработку станет просто невозможно. Проще уж было бы компанию целиком закрыть.
Так и есть, к каждому супругу бывшего сотрудника приставлено по автоматчику с приказом в случае разглашения стрелять на поражение. Если сотрудник был холост, автоматчик приставлен к его коту.
Я склоняюсь к тому, что написать на автомате уже почти привычную всем конструкцию вида std::forward<decltype(self)>(self) и получить универсально работающий код проще, чем принимать решение о необходимости скопировать тело...
Написание на автомате приведет к тому, что вместе с const & и && будет объявляться еще и & перегрузка, а этого часто нужно избегать (нарушение инкапсуляции). Пример -- std::stringstream::str(). Так что нет, deducing this это не волшебная пилюля, позволяющая не думая получать корректный код.
В предложении рассмотрен такой пример. Он признан бессмысленным (такой метод в чём-то схож с operator void(), который никогда не вызывается) и бесполезным, поскольку он просто не может быть найден через unqualified name lookup.
Все так для почти всех методов, но я не просто так использовал operator ==: для него есть дополнительная стадия lookup (reversed operators), в которой резолвится y == x вместо x == y. В этой стадии мы, очевидно, заглянем в member-ы класса Y.
К чему я это все -- наивно думать, что добавление в C++ такой существенной новой вещи как "semi-static member functions" не приведет к никаким новым странным corner-cases. "This paper does not propose any changes to overload resolution" это намерение авторов, а что получится узнаем. spaceship operator тоже задумывался как не меняющий поведение никакого старого кода, а на практике случался миллион breaking changes.
В целом у нас расхождение по принципу оптимист/пессимист. Вы верите, что новые возможности будут использоваться только во благо, а мой опыт подсказывает, что получится как всегда (ну или как много раз было в C++).
А чтобы заставить код работать правильно, сейчас мы должны явно скопипастить тело функции как минимум 3 раза для const&, & и && версий *this.,
Позволю себе слегка не согласиться -- если нужно 3, а не 2 перегрузки, т.е. мы хотим и & ссылку тоже предоставить, то обычно (не всегда) можно быть проще и сделать поле публичным вместо getter-ов.
Перепиши мы код стандартной библиотеки на основе синтаксиса, предложенного в этой бумаге — мы автоматически и по умолчанию получим корректную семантику везде и это очень важно
Чтобы принять решение "вместо обычного нешаблонного getter-а мы будем писать шаблонную функцию с deducing this" все-таки надо задуматься, о том что в этом месте это полезно и пользы больше чем вреда, так что "автоматически" не получится. А если все равно задумываться, то и добавить &&-перегрузку большой проблемой не будет. Более того, с практической точки зрения, принятие "Deducing this" в C++23 никак не поможет починить существующие классы стандартной библиотеки, такие как std::filesystem::path потому что во-первых, они должны компилироваться в C++17-режиме, а во-вторых, ради ABI-stability нельзя отрефакторить non-template перегрузки в template.
... как концепты улучшают жизнь обычных программистов, позволяя упростить написание качественного библиотечного кода...
По-моему, есть существенная разница с концептами -- последние не дублируют существовавшие до них языковые механизмы (не считая SFINAE-хаков вроде enable_if и void_t, по которым никто скучать не будет). Еще одно отличие от концептов, что в теории они могут использоваться и совсем в прикладном коде. Скажем, писать
std::vector<std::uint64_t>::const_iterator beg = myvec.begin();
кажется слишком длинным, а в записи
auto beg = myvec.begin();
кому-то не хватает информации о типе beg, в таком случае
Iterator auto beg = myvec.begin();
может показаться золотой серединой. Правда, пока не прошло достаточно времени, чтобы сказать, пользуется ли такой стиль популярностью на практике.
Непосредственно писать этот код нужно очень малой части C++ программистов, но он при этом косвенно затрагивает буквально каждого пользователя...
Не соглашусь, с тем что только косвенно. Explicit this это прямо новый способ писать member functions, позволяющий отказаться от function ref- and cv-qualifiers. Если бы он был в языке с самого начала, то и отдельный синтаксис для static methods был бы не нужен, и даже, можно пойти еще дальше, и ключевое слово this. В общем я предвижу глобальный раскол по стилю написания member functions (что, согласитесь, существенная часть кода на C++), который мне кажется куда серьезнее, чем войны между остро-/тупо- конечниками адептами trailing/non-trailing return type, east/west const и т.д.
При этом, очевидно, иметь в языке одну фичу (explicit this) лучше чем несколько (function ref- and cv-qualifiers, static methods, keyword this, ...) ну и бонусом те преимущества, что дает нам "Deducing this" proposal, так что если делать язык с 0, то надо идти именно по этому пути, как и сделали в Rust-е. Но добавлять explicit this сверху всего того, что уже есть в C++, по моему мнению принесет больше вреда, чем пользы.
Ну и сверху бонусом "задачка" -- напоминание о том, что языковые фичи интерферируют, и добавляя все новые и новые есть риск завалить язык под их тяжестью:
struct X {};
struct Y {
bool operator == (this X, Y);
};
void test(X x, Y y) {
x == y; // должен ли этот код компилироваться?
}
Я, как ясно из корневого комментария тоже отрицательно отношусь к этому proposal-у, но все-таки, давайте критиковать обоснованно.
virtual functions с explicit this запрещены, так что неявный slicing нам не грозит.
С указателями на функции вроде бы тоже никакой путаницы нет, в этом смысле функции с explicit this ведут себя как статические, для них же никого не напрягает, что указатели это не member-pointers.
Вместо decltype(auto) тоже скорее всего можно написать явный тип, просто не зная что-такое value_ сложно сказать какой. Так что, если не записывать в одну строку, то все не так страшно.
А еще непосредственно в язык были добавлены auto(x) и "Deducing this". 2 фичи, нужные 0.1% пользователей, но усложняющие (добавляющие избыточность) в язык для всех. "Deducing this" в этом смысле, полный караул, auto(x) чуть менее страшно, просто auto теперь может встречаться еще в одном контексте.
При указании параметров концепта нужно задавать все, кроме первого, а первый будет проверяться. Я долго думал, почему Комитет принял именно такое решение, предлагаю подумать и вам.
Потому что последний шаблонный параметр может быть variadic.
А C# стал похожим на язык для пришельцев от добавления async/await, или асинхронный код написанный с async/await проще и понятнее, чем писали до этого (сколько там парадигм было 3 или 4, я не помню)?
Мне кажется, идею 3D-QuickHull можно изложить еще проще.
Выбираем из исходного мн-ва 3 точки принадлежащие выпуклой оболочке. Результат — объединение выпуклых оболочек для подмножества точек лежащих выше и подмножества точек лежащих ниже плоскости, определяемой нашими 3-мя точками.
Мы свели задачу к следующей. Есть 3 точки A, B, C не лежащие на одной прямой и мн-во точек S лежащих над плоскостью P проходящей через A, B, C. Построить оболочку для мн-ва S u {A, B, C}. Решение: выбираем из S наиболее удаленную от P точку D, она в ответ точно входит, разбиваем мн-во S\{D} на 4 подмн-ва:
(0) точки лежащие в тетраэдре (A, B, C, D) (они точно в ответ не попадут),
(1) точки над плоскостью (A, B, D),
(2) точки над плоскостью (B, C, D),
(3) точки над плоскостью (C, A, D).
Для мн-в (1), (2), (3) и соотвественно плоскостей (A, B, D), (B, C, D), (C, A, D) запускаемся рекурсивно.
По вашей ссылке на QuickHull удивительная статья, где геометрическая задача разбирается без единой картинки, это, по-моему, за гранью добра и зла. Если же нормально рассказывать идею алгоритма, используя только термины известные шестикласснику (без симплекса и детерминанта), то, как по мне, в 3D-случае QuickHull гораздо интуитивнее Джарвиса.
В общем-то мой комментарий был к тому, что "зная о такой возможности после прочтения заметки можно найти нужные примеры" немножко не правда, пока что именно про unordered containers качественных материалов нет, и даже самая свежая версия proposal-а P0919 отличается от того что в итоге попало в стандарт.
У типобезопасности и метапрограммных трюков есть некоторая цена, как минимум в эталонной реализации от NVIDIA -- template instantiation stack почти переполняется даже при компиляции hello_world-а. Боюсь себе представить что будет, когда и если этим начнут пользоваться в реальном мире.
Разумеется, это совершенная ерунда. По открытым данным в 2021-м году в JetBrains работало 1900+ человек из них 1500+ в российских офисах. Если почти всех их уволить, продолжать разработку станет просто невозможно. Проще уж было бы компанию целиком закрыть.
Так и есть, к каждому супругу бывшего сотрудника приставлено по автоматчику с приказом в случае разглашения стрелять на поражение. Если сотрудник был холост, автоматчик приставлен к его коту.
https://stackoverflow.com/questions/65648897/c20-behaviour-breaking-existing-code-with-equality-operator
https://stackoverflow.com/questions/66497269/more-silent-behaviour-changes-with-c20-three-way-comparison
https://cdacamar.github.io/wg21papers/proposed/spaceship-dr.html
Написание на автомате приведет к тому, что вместе с
const &и&&будет объявляться еще и&перегрузка, а этого часто нужно избегать (нарушение инкапсуляции). Пример --std::stringstream::str(). Так что нет, deducing this это не волшебная пилюля, позволяющая не думая получать корректный код.Все так для почти всех методов, но я не просто так использовал
operator ==: для него есть дополнительная стадия lookup (reversed operators), в которой резолвитсяy == xвместоx == y. В этой стадии мы, очевидно, заглянем в member-ы классаY.К чему я это все -- наивно думать, что добавление в C++ такой существенной новой вещи как "semi-static member functions" не приведет к никаким новым странным corner-cases. "This paper does not propose any changes to overload resolution" это намерение авторов, а что получится узнаем. spaceship operator тоже задумывался как не меняющий поведение никакого старого кода, а на практике случался миллион breaking changes.
В целом у нас расхождение по принципу оптимист/пессимист. Вы верите, что новые возможности будут использоваться только во благо, а мой опыт подсказывает, что получится как всегда (ну или как много раз было в C++).
Позволю себе слегка не согласиться -- если нужно 3, а не 2 перегрузки, т.е. мы хотим и
&ссылку тоже предоставить, то обычно (не всегда) можно быть проще и сделать поле публичным вместо getter-ов.Чтобы принять решение "вместо обычного нешаблонного getter-а мы будем писать шаблонную функцию с deducing this" все-таки надо задуматься, о том что в этом месте это полезно и пользы больше чем вреда, так что "автоматически" не получится. А если все равно задумываться, то и добавить
&&-перегрузку большой проблемой не будет. Более того, с практической точки зрения, принятие "Deducing this" в C++23 никак не поможет починить существующие классы стандартной библиотеки, такие какstd::filesystem::pathпотому что во-первых, они должны компилироваться в C++17-режиме, а во-вторых, ради ABI-stability нельзя отрефакторить non-template перегрузки в template.По-моему, есть существенная разница с концептами -- последние не дублируют существовавшие до них языковые механизмы (не считая SFINAE-хаков вроде enable_if и void_t, по которым никто скучать не будет). Еще одно отличие от концептов, что в теории они могут использоваться и совсем в прикладном коде. Скажем, писать
std::vector<std::uint64_t>::const_iterator beg = myvec.begin();кажется слишком длинным, а в записи
auto beg = myvec.begin();кому-то не хватает информации о типе
beg, в таком случаеIterator auto beg = myvec.begin();может показаться золотой серединой. Правда, пока не прошло достаточно времени, чтобы сказать, пользуется ли такой стиль популярностью на практике.
Не соглашусь, с тем что только косвенно. Explicit this это прямо новый способ писать member functions, позволяющий отказаться от function ref- and cv-qualifiers. Если бы он был в языке с самого начала, то и отдельный синтаксис для static methods был бы не нужен, и даже, можно пойти еще дальше, и ключевое слово this. В общем я предвижу глобальный раскол по стилю написания member functions (что, согласитесь, существенная часть кода на C++), который мне кажется куда серьезнее, чем войны между
остро-/тупо- конечникамиадептами trailing/non-trailing return type, east/west const и т.д.При этом, очевидно, иметь в языке одну фичу (explicit this) лучше чем несколько (function ref- and cv-qualifiers, static methods, keyword this, ...) ну и бонусом те преимущества, что дает нам "Deducing this" proposal, так что если делать язык с 0, то надо идти именно по этому пути, как и сделали в Rust-е. Но добавлять explicit this сверху всего того, что уже есть в C++, по моему мнению принесет больше вреда, чем пользы.
Ну и сверху бонусом "задачка" -- напоминание о том, что языковые фичи интерферируют, и добавляя все новые и новые есть риск завалить язык под их тяжестью:
Я, как ясно из корневого комментария тоже отрицательно отношусь к этому proposal-у, но все-таки, давайте критиковать обоснованно.
virtual functions с explicit this запрещены, так что неявный slicing нам не грозит.
С указателями на функции вроде бы тоже никакой путаницы нет, в этом смысле функции с explicit this ведут себя как статические, для них же никого не напрягает, что указатели это не member-pointers.
В первом примере ошибка, такой код не скомпилируется. Должно быть
Или, на мой вкус чуть читаемей, так:
Вместо
decltype(auto)тоже скорее всего можно написать явный тип, просто не зная что-такоеvalue_сложно сказать какой. Так что, если не записывать в одну строку, то все не так страшно.https://github.com/cplusplus/papers/issues/293#issuecomment-922673270 (plenary-approved)
https://github.com/cplusplus/papers/issues/115#issuecomment-890138335 (plenary-approved)
А еще непосредственно в язык были добавлены auto(x) и "Deducing this". 2 фичи, нужные 0.1% пользователей, но усложняющие (добавляющие избыточность) в язык для всех. "Deducing this" в этом смысле, полный караул,
auto(x)чуть менее страшно, простоautoтеперь может встречаться еще в одном контексте.Потому что последний шаблонный параметр может быть variadic.
Какую версию clang-а (и libc++) Apple на MacOS ставит мне не ведомо.
https://gcc.godbolt.org/z/q7vKrT
GCC, Clang и MSVC, релизные версии.
Просто современный C++ авторов статьи устарел уже лет на 10. У меня все помещается в строку:
С тем что синтаксис C# пока что полегче я не спорю, и лямбды отличный тому пример. Но синтаксис корутины не усложняют.
Откуда Вы почерпнули информацию, что "Саттер уже подумывает о новом C++ NewLang на замену C++"?
А C# стал похожим на язык для пришельцев от добавления async/await, или асинхронный код написанный с async/await проще и понятнее, чем писали до этого (сколько там парадигм было 3 или 4, я не помню)?
Мне кажется, идею 3D-QuickHull можно изложить еще проще.
S u {A, B, C}. Решение: выбираем из S наиболее удаленную от P точку D, она в ответ точно входит, разбиваем мн-воS\{D}на 4 подмн-ва:Для мн-в (1), (2), (3) и соотвественно плоскостей (A, B, D), (B, C, D), (C, A, D) запускаемся рекурсивно.
По вашей ссылке на QuickHull удивительная статья, где геометрическая задача разбирается без единой картинки, это, по-моему, за гранью добра и зла. Если же нормально рассказывать идею алгоритма, используя только термины известные шестикласснику (без симплекса и детерминанта), то, как по мне, в 3D-случае QuickHull гораздо интуитивнее Джарвиса.
Достаточно одного функтора (в качестве компаратора подойдет
std::equal_to<>), и его можно сделать однострочным:В общем-то мой комментарий был к тому, что "зная о такой возможности после прочтения заметки можно найти нужные примеры" немножко не правда, пока что именно про unordered containers качественных материалов нет, и даже самая свежая версия proposal-а P0919 отличается от того что в итоге попало в стандарт.