Почему пустая оптимизация базового класса не работает?

Почему пустая оптимизация базового класса (EBO) не полностью применяется в Visual С++?

Если у меня много базовых классов, есть ли способ помочь компилятору сделать эту оптимизацию?

#include <iostream>

struct T1 { };
struct T2 { };
struct T3 { };
struct T4 { };
struct T5 { };
struct T6 { };

struct Test : T1, T2, T3, T4, T5, T6 { };

int main() { std::cout << sizeof(Test); }   // Prints 5

Ответ 1

Это давняя ошибка в компиляторе Visual С++. Когда класс происходит из нескольких пустых базовых классов, только исходный пустой базовый класс будет оптимизирован с использованием пустой оптимизации базы (EBO).

Об этой проблеме сообщалось в Microsoft Connect в 2006 году: Пустая оптимизация базы данных не работает должным образом. В настоящий момент старые ошибки не отображаются в Microsoft Connect. Мне сказали, что это временная проблема, хотя я не знаю, когда она будет решена. В то же время, следующий ответ на ошибку от Jonathan Caves, который является одним из разработчиков в команде компилятора Visual С++:

Привет: к сожалению, несмотря на то, что это ошибка в объектной модели Visual С++, мы не можем ее исправить в это время, учитывая, что это исправление потенциально может сломать многие существующие программы по мере изменения размеров объектов. Надеемся, что в будущем мы сможем решить эту проблему, но не для следующей версии продукта.

Спасибо за сообщение о проблеме.

Ответ 2

"Официальная" позиция - MSVC будет выполнять только EBO для одиночного наследования, к сожалению, отчет об ошибке, где это указано, был удален MS, поэтому все, что остается, - это более старый вопрос о MSDN, который указывает на это и ссылается на отчет об удаленной ошибке.

Ответ 3

Начиная с Visual Studio 2017 Update 2, это исправлено... но по умолчанию оно отключено. И вы должны явно включить его для каждого класса отдельно:

    struct __declspec(empty_bases) Test : T1, T2, T3, T4, T5, T6 { };
    //     ^^^^^^^^^^^^^^^^^^^^^^^

    static_assert(1 == sizeof(Test));

К сожалению, это по-прежнему верно даже для /std:c++latest и /permissive- даже в Visual Studio 2019: не существует способа установить его глобально.