LINUX.ORG.RU

Герб Саттер предлагает добавить в С++ метаклассы

 , ,


1

7

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0707r0.pdf

В свежем пропосале Саттер предлагает добавить в С++ механизм для добавления пользовательских мета-типов. Автор отталкивается от наблюдения, что struct это просто class с public:, а enum class это просто class с константами, и предлагает обобщить этот подход и сделать его доступным разработчику. Вот пример реализации аналога interface из Java :

$class interface
{
    ~interface() noexcept {}
    constexpr {
        compiler.require($interface.variables().empty(),
                         "interfaces may not contain data");
        for (auto f : $interface.functions()) {
            compiler.require(!f.is_copy() && !f.is_move(),
                             "interfaces may not copy or move; consider a"
                             " virtual clone() instead");
            if (!f.has_access ()) f.make_public();
            compiler.require(f.is_public(),
                 "interface functions must be public");
            f.make_pure_virtual();
        }
    }
};
// User code (proposed C++)
interface IShape {
    int area() const ;
    void scale_by(double factor);
};
Лично я не верю, что комитет это пропустит, но сам Саттер не последний человек в комитете и понимает, что предлагает.

В C++ уже несколько лет пытаются пропихнуть compile-time reflection и все эти пропозалы похожи друг на друга как две капли воды, в т.ч. с предложением ввести метаклассы.

Ты только в 17-м году их заметил?

utf8nowhere ★★ ()
Ответ на: комментарий от utf8nowhere

Ты только в 17-м году их заметил?

Да. Ну и плюс Саттер это второй человек в комитете после Бьёрна и смотрящий за С++ в VS, если он предлагает, значит вероятность одобрения несколько выше среднего.

nonimous ()
Ответ на: комментарий от ckotinko

в Qt это уже сделано, но еще и тэги можно присобачивать к методам.

а у саттера предложеный код выглядит как говно.

в Qt moc крайне неудобный костыль, но ты сможешь и дальше страдать. всем будет плевать

clover ()
Ответ на: комментарий от ckotinko

а у саттера предложеный код выглядит как говно.

Согласен, но он будет написан один раз разработчиками Qt, после чего все остальные смогут писать просто

QClass MyClass {
    property<int> value { };
    signal mySignal();
    slot mySlot();
};
и это будет компилироваться стоковым компилятором.

nonimous ()

compiler.require

скажите ему что есть static_assert, std::enable_if, type_traits...

во вторых, не нужна «рефлексия вообще». это жабнутые тянут везде свои приблуды как истину в последней инстанции.

нужна возможность рассказать «я предоставляю такое-то api». обычно используют больше одного метода. разве не збс сразу все методы требуемые получить?

ckotinko ☆☆☆ ()
Ответ на: комментарий от ckotinko

во вторых, не нужна «рефлексия вообще». это жабнутые тянут везде свои приблуды как истину в последней инстанции.

то что рефлексия в compile-time тебе не нужна говорит о том что ты всего-лишь говнокодер

clover ()
Ответ на: комментарий от clover

ну объясни, родной, куда и как ты собрался применять рефлексию в С++.

обычно хватает вообще COM c IUnknown, но у програмистов на жабе видимо какие-то свои «паттерны» и «идиомы».

ckotinko ☆☆☆ ()
Ответ на: комментарий от ckotinko

ну объясни, родной, куда и как ты собрался применять рефлексию в С++.

Например, так же, как и в D. Скажем, для того, чтобы можно было автоматически сгенерировать pretty printer для любого пользовательского типа в compile-time. Или чтобы автоматически генерировать operator==. Или чтобы для enum-а можно было автоматически построить to_string. Тут уж все ограничивается только вашей фантазией.

eao197 ★★★★★ ()
Ответ на: комментарий от ckotinko

вообще-то не будет. слоты и сигналы как бы чуток сложнее устроены чем просто методы.

Сигналы - просто методы с генерируемым кодом

Слоты - начиная с Qt 5 в них вообще нет необходимости, можно приконнектить любой метод или вообще лямбду

annulen ★★★★★ ()
Ответ на: комментарий от ckotinko

во вторых, не нужна «рефлексия вообще». это жабнутые тянут везде свои приблуды как истину в последней инстанции.

рефлексия - это то, что отличает человека от зверей </fat>

annulen ★★★★★ ()
Ответ на: комментарий от eao197

Например, так же, как и в D

Честно говоря, ни разу не смотрел как это сделано в мертвом языке с GC. Оно было некрасиво и не Богоугодно, и Господь повелел ему умереть. Тем более что у нас речь идет о С++.

Что касается перечисленых вами примеров, то (по-моему) только pretty_printer для нужд дебага имеет смысл. Что такое «автоматически генерировать оператор ==» я не понял. Оператор же по сути сишная функция с хитрожопым обфусцированным называнием. Получает на вход адрес this, ну и всё как бы. А как тут рантаймовая рефлексия поможет?

Ну можно конечно сделать рантаймовый оператор ==, но практический смысл этого действа я не улавливаю.

Что же касатеся енумов то тут рефлексия как таковая не нужна, и не факт что реализуема. дело в том, что в C++ enum может содержать флаги, значения, а может комбинировать и то и другое. далее их имена - это строки, которые где-то хранятся.

в каком-то бинаре если быть точным. пусть мы знаем, адрес. мы будем на каждый енум писать отдельную функцию для печати? помоему это жирно будет.

а если функция общая, то можно положить её в stdlib, и хранить только байткод для описания енума. а если она в stdlib, то зачем нам рефлексия? нам нужен только байткод в известном формате, который мог бы добываться каким нибудь __builtin_get_enum_desc(typename);

в итоге получаем то же самое, но рефлексии как таковой нету. ну окей. но для этого нужно просто добавить на уровне компилятора в enumы метод to_string(). он просто должен быть и всё.

ckotinko ☆☆☆ ()
Ответ на: комментарий от ckotinko

Что такое «автоматически генерировать оператор ==» я не понял.

Это когда у нас есть структура вроде

struct rectangle {
  int x;
  int y;
  int cx;
  int cy;
};
и мы за счет шаблонной магии и compile-time reflection получаем возможность делать так:
void f(const rectange & a, const rectangle & b) {
  if(a == b) {...}
}

но для этого нужно просто добавить на уровне компилятора в enumы метод to_string(). он просто должен быть и всё.

Вместо того, чтобы расширять компилятор частными случаями, можно было бы сделать рефлексию и позволить создать библиотеки для разных нужд. Какие-то из них могли бы для enum class-а генерировать to_string. Какие-то могли бы operator==() создавать. И т.д.

eao197 ★★★★★ ()
Ответ на: комментарий от ckotinko

во вторых, не нужна «рефлексия вообще». это жабнутые тянут везде свои приблуды как истину в последней инстанции.

Нужна, а ты опять демонстрируешь «ширину кругозора», если кроме джавовской рефлексии ничего не видел и не можешь найти применение для рефлексии времени компиляции.

DarkEld3r ★★★★★ ()
Ответ на: комментарий от clover

то что рефлексия в compile-time тебе не нужна говорит о том что ты всего-лишь говнокодер

От рефлексии до eval не такой длинный путь, так что не столь очевидно, кто тут теперь говнокодер.

kawaii_neko ★★★ ()
Ответ на: комментарий от kawaii_neko

От рефлексии до eval не такой длинный путь, так что не столь очевидно, кто тут теперь говнокодер.

конечно ты, тк именно ты не понимаешь разницу между eval в run-time reflection и compile-time reflection

clover ()

Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.

Неудивительно, что теперь даже в C++ тащят метапрограммирование.

Но, во-первых, среднестатистический дебил, пищущий на C++ этого не оценит, а во-вторых, хватит уже насиловать труп C++, закопайте.

lovesan ()
Ответ на: комментарий от nonimous

Почему-то только до сих пор все тащят фичи из Common Lisp? Да потому что он на годы опередил современные кривые поделия, типа питона, и тем более крестов.

Вот и до compile-time метапрограммирования добрались.

lovesan ()
Ответ на: комментарий от lovesan

Я хотел было ответить, что лиспофаги опять ведут себя, как будто лисп изобрел все, но так подумать, в этом случае действительно ближайшая аналогия это лисп. Даже в D с его метапрограммингом как основной фичей такого нет.

И да, это не означает, что CL не мертв.

nonimous ()
Ответ на: комментарий от lovesan

В этом-то и проблема, что слышу я про него уже лет 15, как до интернета добрался, но видеть его нигде не видно. Но не будем сводить тред к очередному лиспосрачу, право.

nonimous ()
Ответ на: комментарий от theNamelessOne

Для продвинутой сериализации нужно задавать дополнительную информацию. Например, пусть используется механизм Tag-Length-Value (он же ASN1 BER). В этом случае для полей нужно задавать значения Tag. Что-то вроде:

struct rectangle {
  [[tlv-tag=0x25]] int x;
  [[tlv-tag=0x26]] int y;
  ...
}
Но тут уже одной только рефлексией не обойтись, нужна еще и поддержка user-define attributes. А может и не только. Например, бывает необходимо указать, что поле не должно сериализоваться, если оно имеет значение по умолчанию или если выполняется какое-то условие. Скажем что-то вроде:
struct rectangle {
  [[tlv-tag=0x25]] int x;
  [[tlv-tag=0x26]] int y;
  [[tlv-tag=0x27;tlv-store-if=(cx!=cy)]] int cx;
  [[tlv-tag=0x28;tlv-store-if=(cx!=cy)]] int cy;
}

eao197 ★★★★★ ()