Читая о другой теме, я встретил странное поведение, по крайней мере, для меня. Вся эта мысль возникла из специальных взаимодействий между auto и фигурными скобками. Если вы напишете что-то вроде:
auto A = { 1, 2, 3 }
компилятор выведет A как std::initializer_list. Странно то, что подобное правило применяется не только к auto, где могут быть особые причины для него, но и к другим вещам. Если вы пишете следующее:
template<typename T>
void f(std::vector<T> Vector)
{
// do something
}
вы, конечно, не можете называть это так:
f({ 1, 2, 3});
даже если std::vector может быть скопирован инициализирован. Однако, если вы замените std::vector на std::initializer_list, вызов будет работать, и компилятор будет правильно выводить int как тип T Тем не менее, интереснее то, что в первом случае вам нужно #include <vector>, в последнем вам не нужно #include <initializer_list>. Это заставило меня задуматься, и после теста я понял, что каким-то образом std::initializer_list не нуждается в собственном заголовке, поэтому он каким-то образом является частью "базовых" функций.
Более того, для того, чтобы все имело смысл, std::initializer_list должен быть в стандартных объектах более или менее таким же образом, как lambdas являются вызываемыми объектами (в строгом смысле, то есть объектом с operator()). Другими словами, неопределенные согласованные определения должны по умолчанию иметь значение std::initializer_list же как lambdas (в основном) неназванные вызываемые объекты.
Правильно ли это рассуждение? Более того, можно ли изменить это поведение, и если да, то каким образом?
UPDATE: заголовок для initializer_list оказался включенным транзитивно из iostream (действительно странно). Однако остается вопрос: почему вызов работает для std::initializer_list а не для std::vector?