Встроить виртуальную функцию в метод, когда объект имеет семантику значений

Рассмотрим следующий код с шаблоном разработки метода шаблона:

class A {
public:
void templateMethod() {
doSomething();
}
private:
virtual void doSomething() {
std::cout << “42\n”;
}
};
class B : public A {
private:
void doSomething() override {
std::cout << “43\n”;
}
};

int main() {
// case 1
A a; // value semantics
a.templateMethod(); // knows at compile time that A::doSomething() must be called

// case 2
B b; // value semantics
b.templateMethod(); // knows at compile time that B::doSomething() must be called

// case 3
A& a_or_b_ref = runtime_condition() ? a : b;  // ref semantics
a_or_b_ref.templateMethod(); // does not know which doSomething() at compile time, a virtual call is needed
return 0;
}

Мне интересно, может ли компилятор встроить / удалить виртуализацию функции-члена doSomething () в случаях 1 и 2.
Это возможно, если он создает 3 разных фрагмента двоичного кода для templateMethod (): один без встроенного кода и 2 с встроенным A :: doSomething () или B :: doSomething () (который должен вызываться соответственно в случаях 3, 1 и 2)

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

6

Решение

Стандарт не требует оптимизации в целом (иногда он делает все возможное, чтобы их разрешить); он определяет результат, и компилятор должен выяснить, как лучше всего его достичь.

Во всех трех случаях я бы ожидал templateMethod быть встроенным. Затем компилятор может выполнять дальнейшую оптимизацию; в первых двух случаях он знает динамический тип this и поэтому может генерировать не виртуальный вызов для doSomething, (Я бы тогда ожидал, что он встроит эти звонки.)

Посмотрите на сгенерированный код и убедитесь сами.

1

Другие решения

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

Итак, в 3-м случае:

// case 3
A& b_ref = b; // ref semantics
b_ref.templateMethod();

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

И мой компилятор отображает правильно 43 — если бы он отображал что-нибудь еще, я бы немедленно изменил компилятор …

0

По вопросам рекламы [email protected]