cpp-ru / ideas

Идеи по улучшению языка C++ для обсуждения
https://cpp-ru.github.io/proposals
Creative Commons Zero v1.0 Universal
88 stars 0 forks source link

Ключевое слово для класса pinned #125

Open apolukhin opened 3 years ago

apolukhin commented 3 years ago

Перенос предложения: голоса +1, -3 Aвтор идеи: dix75

Часто приходится наследоваться от базового класса без использования его семантики заменяемости(виртуальности). Хотелось бы иметь ключевое слово добавляемое к классу, говорящее компилятору о том, что объект данного класса не будет использоваться(фигурировать) в контексте виртуальности(только как чистый объект) и всего его виртуальные функции теперь трактуются как встроенные (где это возможно).

struct A {
    virtual void exec() = 0;
    virtual void doSMT() = 0;
    virtual ~A() {}
};

struct B: A {
    virtual void exec() override final {}
};

struct C final : B  {
    virtual void doSMT() override final {}
    void clear() {}
};

int main()
{
    C c;
    c.exec();
    c.clear();
}

Вместо final в классе использовать pinned (над словом можно поработать)

Вместо всего кода, компилятор понимал бы, что-то типа этого

struct C   {
    void exec() {}
    void doSMT() {}
    void clear() {}
};

int main()
{
    C c;
    c.exec();
    c.clear();
}

Даже

p.s.

apolukhin commented 3 years ago

yndx-antoshkka, 25 января 2017, 16:50 Не до конца понимаю суть предложения. В данный момент переменные класса помеченного final будет звать виртуальные функции как встроенные (в обход всей виртуализации):

struct C final : B {
    virtual void doSMT() override final {}
    void clear() {}
};

int main()
{
    C c;
    c.exec(); // same as c.C::exec();
    c.clear(); // same as c.C::clear();
}

dix75, 26 января 2017, 11:36 yndx-antoshkka,

  1. В данный момент переменные класса помеченного final будет звать виртуальные функции как встроенные (в обход всей виртуализации): Где такое написано в стандарте такого нет.(Не нашел, был бы признателен , если ткнули пальцем)

  2. Специально проверил asm для gcc.
    vtable for C:
    .quad 0
    .quad typeinfo for C
    .quad B::exec()
    .quad C::doSMT()
    .quad C::~C()
    .quad C::~C()

    Конечно это не показатель.

  3. Хотелось бы видеть то, что для класса С (не будет созаваться виртуальная таблица и др., т.е. отсутствие дополнительных накладных расходов). А чистый класс, в котором для компилятора все известо (все вируальные функции-член и данные-член), Очень упрощенно (появляется некая разновидность POD типа).

yndx-antoshkka, 26 января 2017, 12:43

1. В стандарте нет, но в нём редко прописываются оптимизации. В добавок данную оптимизацию не всегда можно произвести. Информация о том что GCC оптимизирует на основе final есть вот тут https://gcc.gnu.org/gcc-4.9/changes.html "Devirtualization now takes into account anonymous name-spaces and the C++11 final keyword."

2. 3. Если pinned должен ещё убирать таблицу виртуальных функций из базовых классов и всё их содержимое переносить внутрь класса С... тогда это очень интересное предложение, но возникает множество вопросов:

  1. Если тело классов A и B объявлено в отдельном cpp файле, то у нас нет возможности при генерации кода для C сообщить в другую единицу трансляции о том, что все виртуальные вызовы внутри A и B надо девиртуализировать и вызывать функции класса C
  2. Сломается dynamic_cast и catch(A&). При этом для некоторых случаев будет срабатывать, а для некоторых - не будет. Вообще не понятно, как компилятору с таким работать, когда класс A может быть классом с vtable или без него одновременно.

ru.night.beast, 27 января 2017, 12:00 yndx-antoshkka> 3 проще всего сделать так, чтобы компилятор воспринимал класс С как отдельный класс без базы. останутся проблемы 1, но по крайней мере 2 решится.

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

ru.night.beast, 28 января 2017, 13:21 тут подумалось что если все сделать через агрегирование с автоматической генерацией функций, то с 1 и 2 не должно быть проблем.

dix75, 30 января 2017, 11:58 yndx-antoshkka,

  1. Возможность оптимизации основанную на разбрасывании кода в различных единицах трансляции думаю производители компиляторов лучше ответят на этот вопрос.
  2. dynamic_cast сломается , думаю здесь больше сломается. такие вещи и не предпологаются использовать, в любом случаи это будет неопределенное поведение и каждый в праве выбирать, что ему нужно.
  3. Лучше дать компилятору право выбирать, т.е сделать это ключевое слово как рекомендацию компилятору на выполнение данного действия

dix75, 30 января 2017, 12:04 ru.night.beast, Практическая значимость, в отсутствии дополнительных накладных расходов (виртуальная таблица и др). Очень часто базовые классы создаются как интерфейсы(только для переопределения определенных методов) и их использование не предпологается в виртуальности.

yndx-antoshkka, 30 января 2017, 19:11 Как верно заметил ru.night.beast@, если при таком pinned наследовании pinned класс воспринимать как класс без наследования - тогда организовать подобное можно. Базовые классы перестанут быть доступными и кастования от базового класса к pinned классу тоже будет приводить к ошибке компиляции.

Всё ещё непонятно, как решать проблему 1). Многие компиляторы не подразумевают кодогенерацию во время линковки, или подобная кодогенерация существенно замедлит линковку, даже в отладочной сборке. Разработчики компиляторов будут против.

Есть идеи как перенести кодогенерацию на этап компиляции?

ru.night.beast, 2 марта 2017, 10:01 Обсуждение похожего предложения https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/05c474b6-b2e6-4b4f-817b-e3e0bf376a75%40isocpp.org?utm_medium=email&utm_source=footer