Соответствует ли предоставление частного конструктора для initializer_list?

Этот проект стандарта показывает синопсис для initializer_list. У него нет частного конструктора.

http://i.stack.imgur.com/5bc61.png

Но две реализации стандартных библиотек, которые я рассмотрел, libstdc++ и libc++, обе предоставляют частные конструкторы:

  // The compiler can call a private constructor.
  constexpr initializer_list(const_iterator __a, size_type __l)
  : _M_array(__a), _M_len(__l) { }

_LIBCPP_ALWAYS_INLINE
_LIBCPP_CONSTEXPR_AFTER_CXX11
initializer_list(const _Ep* __b, size_t __s) _NOEXCEPT
    : __begin_(__b),
      __size_(__s)
    {}

Я считаю, что часть, где этот частный конструктор "подразумевается", проистекает из §8.5.4/5:

Объект типа std::initializer_list<E> создается из списка инициализаторов, как если бы реализация выделила временный массив из N элементов типа const E, где N — количество элементов в инициализаторе. список. Каждый элемент этого массива инициализируется копированием с соответствующим элементом списка инициализаторов, и объект std::initializer_list<E> создается для ссылки на этот массив.

Итак, мои вопросы:

  • Синопсис не указан?

  • Нужен ли библиотеке частный конструктор? Что он делает, чего не может компилятор?


person user4700874    schedule 22.03.2015    source источник
comment
Похоже, это связано с разрешено ли реализациям добавлять общедоступные члены к стандартным типам?   -  person Shafik Yaghmour    schedule 23.03.2015
comment
Реализациям всегда разрешено добавлять частные конструкторы, которые не меняют поведение правильных программ, но только потому, что две реализации предоставили один и тот же, не означает, что это должно быть указано в стандарте! Какой смысл указывать конструктор, который вы не можете использовать?   -  person Jonathan Wakely    schedule 23.03.2015


Ответы (2)


Синопсис не указан?

Нет, он документирует пользовательские биты шаблона класса initializer_list, части, которые вам действительно разрешено использовать в вашем коде. Согласно синопсису, шаблон содержит только конструктор по умолчанию, позволяющий создавать пустые initializer_list, что явно не очень полезно. Однако тип initializer_list<T> зависит от некоторой магии, выполняемой компилятором. По волшебству я имею в виду §8.5.4/5, который вы процитировали. Это позволяет следующему оператору быть законным и компилируемым.

std::initializer_list<int> numbers{1, 2, 3, 4}; // no such constructor in the synopsis

Здесь, как объяснялось в §8.5.4/5, компилятор создаст массив, содержащий четыре целых числа, а затем инициализирует экземпляр initializer_list<int> либо парой указателей (первый элемент и один после конечного элемента), либо указателем и длиной (это то, что делают как libstdС++, так и libС++).

После создания экземпляра ваш код получает доступ ко всем функциям-членам, перечисленным в обзоре.

Нужен ли библиотеке частный конструктор? Что он делает, чего не может компилятор?

Как следует из комментария выше определения закрытого конструктора libstdc++, компилятор способен генерировать код, который обходит обычный контроль доступа, поэтому нет, я бы сказал, что наличие этого конструктора необязательно. Компилятор может использовать конструктор по умолчанию для создания пустого экземпляра initializer_list, а затем присвоить соответствующие значения закрытым элементам данных (они также не перечислены в обзоре, но необходимы).

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

person Praetorian    schedule 22.03.2015
comment
Этот общедоступный конструктор по умолчанию также необходим для работы std::initializer_list<int> numbers{};. - person T.C.; 23.03.2015

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

Действительно, §17.6.5.5 (проект № 3797) гласит:

Вызов сигнатуры функции-члена, описанной в стандартной библиотеке C++, ведет себя так, как если бы реализация не объявляла никаких дополнительных сигнатур функций-членов.

Сноска 189:

189) Допустимая программа на C++ всегда вызывает ожидаемую библиотечную функцию-член или функцию с эквивалентным поведением. Реализация также может определять дополнительные функции-члены, которые в противном случае не вызывались бы допустимой программой на C++.

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

Относительно std::initializer_list

Нужен ли библиотеке частный конструктор? Что он делает, чего не может компилятор?

Стандарт определяет, что вы ожидаете при создании std::initializer_list<T> из списка инициализаторов. То, как это делается, определяется реализацией, и, как сказано выше, он может вызывать конструктор private.

person edmz    schedule 22.03.2015