1. C++ / Говнокод #26637

    +3

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    template<typename T>
    concept Addable = requires (T x) { x + x; }; // requires-expression
     
    template<typename T> requires Addable<T> // requires-clause, not requires-expression
    T add(T a, T b) { return a + b; }

    все решено.. перехожу писать код на "конецепты"

    Запостил: ASD_77, 05 Мая 2020

    Комментарии (91) RSS

    • SFINAE сдохни падла в адском огне
      Ответить
    • Ничего не понятно
      Именно поэтому я за js, ведь там можно не проверять Addable потому что и так можно сложить любую хуйню с любой хуйней
      Ответить
      • ... и получить хуйню.

        Реальные примеры:
        []+{} === "[object Object]";
        {}+[] === 0;
        Ответить
        • Ну и что? Если что-то где-то не работает, то всегда потом можно исправить
          Ответить
          • Действительно, пользователи по обратной связи пришлют вопрос: «Что такое [object Object] и почему у меня на счёте NaN рублей?»
            Ответить
            • Ну у всех бывают баги, даже у опотных программистов.

              А в С++ бы такой код вообще не скомпилировался. Что, лучше было бы?
              Ответить
              • Learn C, instead of just stringing random characters together until it compiles, как завещал Линус Торвальдс.
                Ответить
                • Проще выучить J и писать рандомные символы пока не выполнится.
                  Ответить
                  • Проще на «PHP».
                    Ответить
                  • Неправда. Будет много невалидных вореций. J очень капризный, и еггоги выдаёт малоговорящие, кроме "spelling error" и "domain error" (самая частая) других слов не знает.
                    Ответить
            • А ещё "NaN" можно локализовать и получить "не число рублей", что бы пользователю было проще и понятнее.
              Ответить
              • А давайте дружно позовём функцию toLocaleString!

                https://govnokod.ru/26038#comment513100
                Ответить
        • Конечно ебать, кто в 2020 использует "+"
          const {add} = require('ramda')
          add({}, []) // NaN
          add([], {}) // NaN
          Ответить
          • var add = _curry2(function add(a, b) {
              return Number(a) + Number(b);
            });


            Интересно...
            Ответить
            • Что это за хуйня?
              Ответить
              • Исходник функции add из пакета «ramda».
                Ответить
                • Лично я когда пишу "npm install ramda" получаю бинари скомпилированные рептилоидами из хаскелля так что понятия не имею о чем ты
                  Ответить
          • ахахаха, жопаскриптеры лечат баги своего говноязыка библиотеками

            Сука, язык настолько хуёвый, что даже сраный оператор сложения в нем приходится заменять
            Ответить
            • да, да, обосрал js, молодец, иди возьми с полочки мышьяк
              Ответить
              • Yо ведь он прав.
                Это же какой-то ёбаный стыд, что для простого сложения надо ставить пакет.
                Ответить
                • Да он бля 100% прав, только разговор не о том. Уже 1234 раз обсосали что механика сложения в жс полная хуета и когда об этом душнят в 1235 раз я расстраиваюсь
                  Функция в библиотеке находится для других целей - чтобы создать функциональную обертку над операторами
                  Ответить
                  • Почему в других языках функциональщина из коробки?
                    Ответить
                    • библиотека ramda имеет 2 основных отличия от более традиционных библиотек:
                      1)аргументы-данные находятся в функциях высшего порядка на последнем месте
                      2)функции все каррированы по дефолту
                      Покажи мне мейнстрим язык где это поддерживается из коробки
                      Ответить
                      • >1)аргументы-данные находятся в функциях высшего порядка на последнем месте

                        Не очень понял. Приведи пример

                        >2)функции все каррированы по дефолту
                        Зачем делать что-то по дефолту"?
                        Каррировние есть и в питоне (partial), да и в руби (Proc.curry)
                        Ответить
                        • Рассмотрим на примере:
                          Задача: найти сумму всех квадратов четных чисел
                          Условие: ты ебнутый функциональщиной петух
                          Underscore
                          const range = _.range(1, 17)
                          const reducer = _.compose(
                             _.partial(_.reduce, _, (res, curr) => res + curr, 0),
                             _.partial(_.map, _, _.partial(Math.pow, _, 2)),
                             _.partial(_.reject, _, val => Boolean(val % 2))
                          )
                          reducer(range)

                          Ramda:
                          const range = R.range(1, 17)
                          const flow = R.compose(
                            R.reduce(R.add, 0),
                            R.map(R.flip(Math.pow)(2)),
                            R.reject(x => Boolean(x%2))
                          )
                          flow(range)

                          Второй пример смотрится почище по-моему, за счет того, что:
                          1) функции каррированы, не надо ебать себе мозг partial на каждом вызове
                          2) место массива в map, filter и reduce - в конце списка аргументов во втором случае, благодаря чему не надо засирать код _ плейсхолдером, обозначая его место.
                          Пример полное говно, но надеюсь что по нему видно, насколько этидве особенности упрощают композицию функций
                          Ответить
                          • export default function _arity(n, fn) {
                              /* eslint-disable no-unused-vars */
                              switch (n) {
                                case 0: return function() { return fn.apply(this, arguments); };
                                case 1: return function(a0) { return fn.apply(this, arguments); };
                                case 2: return function(a0, a1) { return fn.apply(this, arguments); };
                                case 3: return function(a0, a1, a2) { return fn.apply(this, arguments); };
                                case 4: return function(a0, a1, a2, a3) { return fn.apply(this, arguments); };
                                case 5: return function(a0, a1, a2, a3, a4) { return fn.apply(this, arguments); };
                                case 6: return function(a0, a1, a2, a3, a4, a5) { return fn.apply(this, arguments); };
                                case 7: return function(a0, a1, a2, a3, a4, a5, a6) { return fn.apply(this, arguments); };
                                case 8: return function(a0, a1, a2, a3, a4, a5, a6, a7) { return fn.apply(this, arguments); };
                                case 9: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8) { return fn.apply(this, arguments); };
                                case 10: return function(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9) { return fn.apply(this, arguments); };
                                default: throw new Error('First argument to _arity must be a non-negative integer no greater than ten');
                              }
                            }


                            Эх, а я хотел подставить функцию 42 аргументов...
                            Ответить
                            • Перевёл на «PHP»:
                              function _arity($n, $fn) {
                                  return function() use ($n, $fn) { return call_user_func_array($fn, array_slice(func_get_args(), 0, $n)); };
                              }
                              Ответить
                          • Хрень какая-то. Еще и задом наперед.
                            Вот в Ди все проще: iota(1,17).filter!"a%2==0".map!"a*a".fol d!"a+b"
                            Ответить
                            • Красиво. Синтаксис явно придумал человек, знакомый с «J» или с «APL».
                              Ответить
                              • Синтаксис близок к плюсам.
                                После подстановки строковых параметров шаблонных функций получится
                                iota(1,17).filter!(a => a%2==0).map!(a => a*a).fold!((a,b) => a+b)

                                Все благодаря кодогенерации в компайл-тайме. Считай это работает как eval в пхп.
                                Ответить
                                • > как eval

                                  Но с проверкой синтаксиса и типов, оптимизацией и т.п.
                                  Ответить
                                • Если бы не фича Uniform Function Call Syntax то тоже пришлось бы функции задом наперед вызывать.
                                  А так даже можно 1.iota(10)
                                  Ответить
                                  • > задом наперёд

                                    Да это просто математики до программирования дорвались. Если забыть о том, как композиция писалась в математике, то никто не мешает в compose функции в прямом порядке передавать.
                                    Ответить
                              • Говно какое-то придумал, в J гораздее более читаемо:
                                +/ *: (#~ =&[email protected]|~&2) 1 + i.17
                                Ответить
                          • Ебать, как же функциухи любят оверинжиниринг!
                            s = 0
                            for x in range(1, 17):
                                if x % 2 == 0:
                                    s += x ** 2

                            Или вообще:
                            s = 0
                            for x in range(2, 17, 2):
                                s += x ** 2
                            Ответить
                            • Гдеьздесь функцитуха?
                              Ответить
                              • В комментарии, на который я отвечал.
                                Ответить
                                • Аа, я думал у тебя оферинженирная цитушня.
                                  sum(x**2 for x in range(2, 17, 2))
                                  Ответить
                                  • Точно, так вообще заебись.
                                    Ответить
                                  • Что это за питушня? Как можно так писать? Хаскелябры поимели сердечные приступы.

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

      Или вот эта хрень с нечитаемыми концептами с мутным синтаксисом. То ли дело в Ди:

      bool isAddable(T)() { T a; return __traits(compiles, a+a); } //просто шаблонная функция
      bool isConcatinable(T)() { T a,b; return __traits(compiles, a~b); }

      T add(T)(T a, T b) if(isAddable!T) { return a+b; } //без извратов проверяем подходит ли тип
      T add(T)(T a, T b) if(isConcatinable!T) { return a~b; }
      Ответить
      • Ну такая себе синтетика.
        Разве в D компилятор сам не догадается проверить, есть ли у оператора + нужная перегрузка?

        Интересно было бы почитать, как эта херня используется в реальных примерах.
        Ответить
        • тогда ошибка неоднозначности возникает. Видимо методы только по сигнатуре проверяются. В плюсах тоже нельзя две одинаковых шаблонных функции создать с разным кодом.
          Ответить
          • Когда мы пишем
            a+b
            без всяких шаблонов,
            там под капотом не проверяется, что есть перегрузка + для операндов указанных типов? Или в D нет перегрузки операторов?
            Ответить
            • Перегрузки - есть. Простой вариант с одним объявлением T add(T)(T a, T b) { return a+b; } отлично работает.
              Ответить
            • Да иногда просто надо 2 разных реализации - например общую и оптимизированную. И одну из них надо отключить по условию, чтобы для каждого типа реализация была только одна. Сигнатура то у обоих реализаций одинаковая.
              Ответить
              • Две реализации сложения? Вот это вы там развлекаетесь у себя в крестах, сеньоры!
                Ответить
                • ну а вдруг. Одна нормальная, а вторая как в js - ебанутая.
                  Ответить
                  • Но я всё равно не понимаю, почему этого нельзя сделать без шаблонов. Но я почти не знаю крестов на этом уровне, потому могу ерунду сказать.

                    Если есть перегрузка операторов, то зачем тогда нужны шаблоны? Или оператор это чисто пример в этом случае, а с функциями перегрузка не прокатит?
                    Ответить
                    • > если есть перегрузка, зачем тогда шаблоны

                      А чтоб ты заебался готовиться к собеседованиям. В мире не так много людей, которые с первого раза правильно ответят на вопрос, "а что именно вызовется если у меня есть десяток обычных перегрузок и ещё пяток шаблонов".

                      > нельзя сделать без шаблонов

                      Ну потому что условие зачастую не для конкретных типов A, B и C, а для типов, у которых есть метод foo(). Обычные перегрузки так не могут.
                      Ответить
                      • Ты имеешь в виду ситуацию типа

                        T add(T)(T a, T b) { return a.foo(b); }
                        ,

                        когда T произволен и все возможные T вообще ничем не ограничены, в том числе абстрактным родителем?

                        А такой пример вообще скомпилируется? Или в крестах, как и в D, главное, чтобы он был синтаксически правильным, а семантика проверяется для конкретной подстановки?
                        Ответить
                        • Да, семантика проверяется для конкретной подстановки
                          Ответить
                          • Понятно. Я как-то обескуражен.

                            А я ещё хотел узнать, а зачем в крестовых шаблонах можно указывать не только типы, но и значения? Это где-то реально используется?

                            Это чтобы можно было делать типы Matrix<4, 4>?
                            Ответить
                            • Ну да, и всякие std::array<int, 100500>
                              Ответить
                            • Где-то на «Говнокоде» даже был пример факториала в компайлтайме на крестошаблонах.
                              Ответить
                              • Ну мы всё-таки про нормальный код, а не метушню.
                                Ответить
                        • Да, причём есть правило SFINAE (substitution failure is not an error). Т.е. если шаблон раскрылся в хуйню, которая не компилится, то ошибка игнорится, а этот шаблон просто выбрасывается из кандидатов.
                          Ответить
                        • Кресты не могут проверить синтаксис, не зная семантики, потому что грамматика контекстно-зависимая. Борманд недавно приводил пример a <b,c> d, который может раскрываться как в два сравнения, так и в специализацию шаблона, в зависимости от типов a, b, c, d.

                          А Тарас вообще привёл хакерский пример:
                          https://govnokod.ru/14365
                          Ответить
                          • То есть фраза из мануала по D "The body of the TemplateDeclaration must be syntactically correct even if never instantiated. Semantic analysis is not done until instantiated" к C++ неприменима? В шаблоне может быть любое ололо?
                            Ответить
                            • Какую-то меру знать надо. Фигурные скобки должны быть сбалансированы, иначе компилятор не узнает, где конец шаблона. А полный разбор синтаксиса происходит при инстанциации, потому что, например, без знания типов нельзя определить, должны ли быть < и > парными или нет.
                              Ответить
                              • > без знания типов нельзя определить

                                Ну это старые мсвц не могли. А все остальные работают в 2 фазы. И если ты не написал typename - значит это значение. Т.е. a<b,c>d по-умолчанию распарсится как операторы сравнений.
                                Ответить
                                • Еще вспомни выражение a * b = c. Это объявление указателя или что-то еще?
                                  Ответить
                                  • Ну если a зависит от параметра шаблона, то это умножение.
                                    Ответить
                                    • В Ди это всегда объявление указателя. Проверка типа для a не выполняется.
                                      Если же нужно умножение, то надо явно писать (a*b)=c при наличии оператора *, возвращающего lvalue.

                                      "Any ambiguities in the grammar between Statements and Declarations are resolved by the declarations taking precedence."
                                      Ответить
                                    • Главное в мокросах так не писать.
                                      Ответить
                                  • > a * b = c
                                    - это что ещё за покемон? А, главное, зачем так писать?
                                    Ответить
                                    • = c лишнее

                                      char * s
                                      count * size
                                      Ответить
                                      • А, я забыл про перегрузку апиратороу.
                                        Ответить
                                      • Согласен. Тогда это уже в сишке работает. Какой багор )))
                                        Ответить
                                    • Это уравнение. Вдруг там перегрузки так сделаны, что оно решает уравнение и помещает результат в не const переменную.

                                      const int a = 42;
                                      int b = 0;
                                      const int c = 100500;

                                      a * b = c;
                                      Ответить
                                      • Именно поэтому я за «Prolog».
                                        Ответить
                                      • Можно даже системы уравнений решать
                                        solve( 3*a+5*b=c, 7*b-8*d=5*c)
                                        Вот вам и специальная олимпиада по написанию такой штуки.
                                        Ответить
                            • В Ди грамматика контекстно-свободная. Многих непоняток из плюсов нет вообще.
                              Ответить
                          • Хотя из этой темы, на которую ты привёл ссылку, я подчерпнул, что любое ололо может быть только у msvc.

                            Значит, у других всё же синтаксическая проверка осуществляется.
                            Ответить
                            • Кажется с VS 2019 завезли двухфазное инстанциирование шаблонов, которое давно было в clang и gcc. Скорее всего теперь не любое ололо можно тыкать в шаблоны.
                              Ответить
                      • >перегрузок и ещё пяток шаблонов
                        А чтобы не скучать, есть еще параметры по умолчанию
                        Ответить
                        • И специализации шаблонов.
                          Ответить
                          • и пара опечаток
                            Ответить
                            • После которых конпелятор вываливает тебе весь список из тысячи кандидатов на оператор << и расписывает почему они не подошли.
                              Ответить
                          • И управление их инстанциированием еще
                            Ответить
                      • > А чтоб ты заебался готовиться к собеседованиям. В мире не так много людей, которые с первого раза правильно ответят на вопрос, "а что именно вызовется если у меня есть десяток обычных перегрузок и ещё пяток шаблонов".

                        Я так понимаю, на этот вопрос нужно ответить, но не стоит отвечать правильно?

                        А. "А хрен его знает?" - кандидат не знает C++, нам такой не нужен.

                        Б. "Сначала то, а потом то, при условии таком-то, ссылка на параграф стандарта такой-то" - кандидат поехавший, он нам либо весь код в неподдерживаемую, но корректную с точки зрения стандарта питушню переведёт, либо как-то раз память его подведёт, и он самонадеянно допустит UB, пока коллеги пишут "(a == b) || (c == d)" вместо "a == b || c == d", нам такой вообще ни за что никогда не нужен (кандидата А ещё можно научить, а этот петух Б нам все проекты на дно утянет).

                        В. "А хрен его знает, но там есть свой установленный стандартом порядок, искать нужно там-то, ключевые слова для поиска такие" - вот это нормальный кандидат, этого берём.
                        Ответить

    Добавить комментарий