Читая о другой теме, я встретил странное поведение, по крайней мере, для меня. Вся эта мысль возникла из специальных взаимодействий между 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
?