Comments 28
Боже мой, похоже что Филипп Розеен это еще один Александреску :)
Самое страшное, что оно сейчас расползется, все начнут это использовать, потом в Бусте что нибудь появится, и потом это станет нормой.
Так никто ж не заставляет вас это трогать. Если бы такая фишка как «счетчки времени компиляции» была встроенна в язык, это было бы еще большей магией.

Так что пусть живет.
Это не было бы магией, хотя не было бы и полным решением проблемы («счетчики времени компиляции» — лишь крошечная часть того, что можно сделать, получив доступ к императивному метапрограммингу).
Я вот в предыдущем посте по С++ высказался насчет того, как я вижу идеальный вариант метапрограммирования — так заминусовали. А эта дикая смесь constexpr, шаблонов и friend объявлений уже есть, и ей будут пользоваться, получая в очередной раз километровые сообщения об ошибках компиляции. И трогать придется, потому что реальные задачи требуют хоть каких-то решений, и за неимением других придется пользоваться этим.
Там заминусовали за упоминание javascript в в контексте святая святых плюсов — компилятора. Тема с прямым доступом к AST была, вроде, нормально воспринята.
Именно так. «Дикую смесь constexpr, шаблонов и friend объявлений» именно потому и терпят, что она «уже есть» — как известно метопрограммирование в C++ было не сознательно добавлено, оно было открыто! Если уж сознательно добавлять — то нужно делать «по уму», а не путём вкручивания в язык, где и так полно костылей, ещё одного, причём весьма немаленького масштаба.

Да, это правда, что на стандартном C++ (без дополнительных библиотек) тяжело работать с AST, деревьями и прочими подобными вещами. Но это нифига не повод вкручивать в компилятор совершенно другой язык с совершенно другими «правилами игры» — это повод расширить стандартную библиотеку, не более того.
Концепция С++ мне видится в том, что в ядре языка находится минимум функциональности, и та ее часть, которая в других случаях переносистя в ядро (ну, поддержка модификации AST — Тоже фича ядра языка), находится в стандартной библиотеке. Если же вам нужен доступ к AST, то переходите на Erlang :)

А про «трогать» я имел в виду реализцию. Кто-то в бусте реализовал это — ну и пусть себе там будет. Вам-то какое дело, как оно там устроено? Длинные ошибки компиляции сейчас, тем более, в принципе исправлюятся static_assert-ами.

Лучше всего это сформулировал, как обычно, Джоэл: Интересно, что историю развития C++ можно описать как историю затыкания дырок в абстракции строк.

Последнее достижение на этом пути, как всем известно, появилось в C++14, но замечание Уж не знаю, отчего бы не добавить к языку элементарный класс строчек в силе: абстракция всё ещё протекает и понятно, что её будут «латать» и дальше (к примеру засунуть std::string в rodata по прежнему нельзя).
Длинные ошибки компиляции сейчас, тем более, в принципе исправлюятся static_assert-ами.


К сожалению, пока не появятся концепты, мы будем прозревать от ошибок, воспеваемых в постах вроде этого с генерацией длиннейшего сообщения об ошибке.

Хотя во многих случаях static asserts могут помогать, это да.
Зато с языком, в котором нет магии, вы не сможете почувствовать себя волшебником :)
А потом Филипп устает от этой магии и пойдёт пилить язык E основной фишкой которого станет императивное программирование времени компиляции :-)
Я дико извиняюсь, но что означает конструкция int = sizeof (dependent_writer <B>) ?
Тут просто имя пропущено. Оно ведь не нужно, параметр все равно нигде не используется. По сути это просто еще один шаблонный параметр со значением по умолчанию.

Вот тут, например, видно, что имя только опционально указывается в этом синтаксисе.
UFO landed and left these words here
За наличие таких техник бить по лицу ссаными тряпками авторов кривых стандартов надо. И запрещать к чертям не прикрываясь идиотским «ни можем, совместимость поломаем, агу-агу».
Шикарная статья! И переводчик не подкачал. При всей сложности вопроса всё описано настолько понятно, что просто диву даёшься. Жду перевода остальных статей!
Я не силен в метамагии, но насчет прослойки dependent_writer — может можно убрать вот так:
constexpr int flag(int);

template <bool b>
struct writer
{
    friend constexpr int flag()
    {
        return 0;
    }
};

template <
    bool B = noexcept (flag(0)),
    typename T = writer <B>
>
constexpr int f()
{
    return B;
}

int main()
{
    constexpr int a = f();
    constexpr int b = f();

    static_assert (a != b, "fail");
}
Однако же не работает! (gcc-4.8.2)
t4.cc:29:5: error: static assertion failed: fail
static_assert (a != b, «fail»);
Видимо выражение typename T=writer<B> не вычисляется т.к. Т не используется.

Да, здесь получается контекст, который не требует, чтобы writer <B> был complete type. Поэтому и использовался sizeof, для принудительного инстанцирования.

Но вообще это довольно интересный вопрос — почему бы не добавить зависимость от B в сам writer. Если сделать, как выше написали, (т.е. совсем убрать Tag из writer, а вместо него добавить B), то получится, что каждая из специализаций writer (для true и для false) попытается создать определение для flag, и нарушится one definition rule. То же самое произойдет, если оставить в writer оба параметра (Tag и B) — для каждого их набора будет попытка сгенерировать отдельное определение flag, и уже во время второй генерации все покрашится.

А dependent_writer все свои специализации (и для true == B, и для false == B) наследует от единственной специализации writer <int>, поэтому определение flag будет сгенерировано только однажды, и ODR не нарушится.
Надо обдумать не спеша, и вообще мне кажется если завернуть это покрасивее то уже вполне можно пользоваться.
Вот только еще осознать где и как это лучше применить.
Не работает — это в смысле работает?) Ведь целью и было получить заданный assert. Я проверял на VC++15
Нет. Assert не вывалится, когда a не равно б, что и явыляется целью
По-моему Вы путаете — цель статьи показать, что constexpr-функции могут возвращать разные значения. Для этого и добавлен assert(a!=b) — чтобы показать, что можно добиться разных значений. И этот assert должен сработать, чтобы показать, что мы таки получили разные значения.
нет. он сработает, если значение одинаковые.

assert(5 != 5); //сработает
assert(4 != 5); //не сработает
Наверное, насчет static_assert немного двусмысленно получилось в статье. Под «срабатыванием» подразумевалось именно прохождение ассерта, т.е. нормальная компиляция без ошибки. А ошибки не будет, если условие ассерта true, чего нам и надо. Иначе говоря, если код работает, и значения различаются, то все компилируется нормально. Я перефразировал в самой статье и обновил.
Спасибо за перевод, давно на Хабре таких жемчужин не было!
Only those users with full accounts are able to leave comments. Log in, please.