Category: общество

Category was added automatically. Read all entries about "общество".

Vash

options = options || {}; или обращение к говнокодерам на JS

Давайте поговорим про джаваскрипт. А точнее, про омерзительную традицию, которая лезет во все библиотеки npm из тормозного насквозь jQuery: про передачу аргументов ассоциативным массивом.

Ребята, зачем так делать? Я понимаю, что упоротые по никсам программисты не получают никакого когнитивного диссонанса, говоря про unix way и single responsibility, делая программы с туевой хучей аргументов командной строки, и потом пытаясь через man man понять, как ими пользоваться, через history вспомнить, как это, блядь, делалось, и через лишний пробел в rm почистить себе весь диск. Но должны же быть адекватные люди, да?

Ребята, этот подход не модульный. Вы никогда не вынесете в опции всё, что мне хотелось бы пофиксить внутри вашей убогой библиотеки. Зачем, зачем вы продолжаете это делать? У вашего кода слишком маленький memory footprint? Он слишком мало тормозит? JIT слишком хорошо понимает, как убрать оттуда весь дохлый код, которого у вас там 90% для отдельного применения либы?

Ботайте, блин, Хаскелл, делайте комбинаторы, экспозьте API из элементарных запчастей, пусть пользователь собирает.
Vash

Curring in C++

Как просто каррировать функцию на С++ (код): оборачиваем указатель на функцию во враппер, который перегружает оператор применения, который конструирует объект вложенного класса, передавая ему указатель, и у которого перегружен оператор применения, который уже и вызывает оригинальную функцию.

Ну это как-то некрасиво. Нужно сделать это через лямбды (код). Боромир подсказывает, что нельзя так просто взять и узнать, какого типа у лямбды аргументы, и что она там себе возвращает. Сначала нужно уяснить, что лямбда это безымянный класс с перегруженным оператором применения, который ещё и объявлен, как неизменяющий, поэтому тип лямбды нам не скажет ничего, а тип её operator () скажет. Несколько минут брутфорса подсказывают, что есть только один способ правильно взять его тип:
typedef decltype(f) temp;
typedef decltype(&temp::operator()) type;

Подстановка тела temp, отсутствие взятия адреса и прочие мелочи делают код некомпилируемым, но это у меня, видимо, скилла не хватает.

Получив тип, запасаемся оптимизмом, ведь в стандартной библиотеке, в отведённом месте нет и подобия на функции, которые позволят разобрать неизменяющий указатель на метод. Появляется чуток бойлерплейта, который, конечно, нужно вынести в инклюд. Теперь мы можем в С++ писать мономорфные типы из Haskell. Я от радости написал там же ещё и композицию.
Vash

CRTP и два наследования

Возник небольшой трабл. У меня есть метафункция
template <typename T>
struct f { .. };
и есть просто некоторый тип
template <typename T>
struct g { ,,, };

Значения аргумента нужно разделить на две категории
1. Тип, унаследованный от нашего g, и для него определить параметр
2. Все остальные типы

Отделить зерна от плевел нелегко. Сначала я попробовал добавить поле result в g, а затем проверить его наличие.
template <typename T>
struct check {
    struct result {};
    struct child : T {
        // Если в T нет result, то замкнется тот, который чуть выше
        typedef result type;
    };
    typedef typename equals<result, typename child::type>::type type;
};
Я жесточайшим образом обломался, поскольку от типа T наследовать можно далеко не всегда. Например, если это enum. int или union.

Затем я еще долго мучался, пытаясь отделить сначала ненаследуемые типы, а затем применить этот трюк.

Наконец, мне в голову пришла мысль "хм, а ведь есть CRTP". Например, его можно применять так:
template <typename T> struct CRTP {};
template <typename T> struct f : CRTP< f<T> > {};
template <typename T, typename U>
typename mix<T, U>::type operator + (CRTP<T> x, CRTP<U> y) { ... }
пользуясь им в качестве статического способа обеспечения полиморфизма.
К сожалению, pattern matching ничего не знает о наследовании, и тип f, унаследованный от CRTP все равно считает типом f.

Я совсем разозлился, открыл Boost, нашел в нем is_bas_of<B, D>, и заюзал следующим образом:
struct x {};
template <typename T> struct g : x { ... };
struct z : g<int> { ... };
template <typename T>
struct check {
    typedef typename boost::is_base_of<x, T>::type type;
};
что сразу же отлично заработало.

Это бы меня и не волновало дальше, если бы любопытность не заставила меня заглянуть в исходники boost. Там я увидел, что эта штука полагается на нестандартные возможности компиляторов (впрочем, в VS, gcc и многих других они есть), а для всех остальных попросту возвращает true.

Люди, это не дает мне спать. Спасите меня кто-нибудь, ну пожалуйста.

UPD: решено благодаря комментариям jtootf, подогревшим мой интерес.
#include <iostream>
using namespace std;
struct e { void tester(); };
template <typename T>
struct f : e { };
struct g : f<int> {};
struct m {};
template <class T>
class check {
    template <typename T, T> struct TypeCheck;
    typedef char Yes;  typedef long No;
    template <typename T> static Yes chk(TypeCheck<typename void (e::*)(), &T::tester >*);
    template <typename T> static No  chk(...);
    static bool const value = (sizeof(chk<T>(0)) == sizeof(Yes));
};
template <typename T, bool chk = check<T>::value>
struct h { static const int value = 0; };
template <typename T>
struct h<T, true> { static const int value = 1; };
int main () {
    cout << h<g>::value << endl;
    cout << h<m>::value << endl;
    cout << h<int>::value << endl;
    system("pause");
}