Подтвердить что ты не робот

Является ли кортеж гарантированным сжать пустые элементы?

Реализации std::tuple в libstdС++ и libС++ используют (я полагаю) пустую оптимизацию базового класса для сжатия пустых элементов:

struct empty {};

static_assert(sizeof(std::tuple<int, empty>) == sizeof(int), ""); // (1)

Мой вопрос в том, просто ли это поведение, установленное стандартом? То есть, могу ли я полагаться (1) всегда быть истинным для стандартно-совместимой реализации?

4b9b3361

Ответ 1

Нет, это не гарантировано. С++ 11 § 20.4 (глава о std::tuple) вообще не упоминает размер типа. Таким образом, нет никаких гарантий относительно того, как организованы члены в кортеже. Любая оптимизация с пустым основанием и аналогичные эффекты являются исключительно проблемой качества реализации.

Обратите внимание, что это означает, что даже нет гарантии, что std::tuple<int, char> будет сохранен в памяти как int, за которым следует char, а не наоборот. Макет объекта std::tuple полностью не указан.

Ответ 2

Нет. Это не. На самом деле есть места, когда вы вообще не можете пустую базовую класс.

Стандарт С++ указывает, что два разных объекта должны иметь разные адреса.

рассмотрим следующее: std::tuple<char, empty, empty>. Независимо от того, как вы выглядите (состав, наследование), у вас есть два объекта empty, которые должны иметь разные адреса. Это увеличит размер кортежа хотя бы на 1.

Проблема может возникнуть из-за косвенного наследования:

struct derived: empty
{
    char i;
};
std::tuple<derived, empty>

Здесь у нас есть два объекта empty внутри одного класса, и у них также должны быть разные адреса, поэтому вы не можете оптимизировать второй член empty из кортежа.

EDIT: обнаружено неожиданное поведение с пустым основанием и aligned_storage, вытекающее из агрессивного EBO: http://coliru.stacked-crooked.com/a/f45de2f889151ea3