Я заметил следующие векторные конструкторы в стандартной библиотеке C ++
explicit vector(size_type n);
vector(size_type n, const T& value, const Allocator& = Allocator());
Есть ли причина, по которой второй конструктор не помечен explicit
? Это компилирует и заставляет меня чувствовать себя плохо
void f(vector<string>);
int main() {
f({10, "foo"});
}
Хотя если я опущу "foo"
, он не компилируется, и это то, что я ожидаю, когда передаю парное (составное) значение типа int и строку в функцию, которая хочет вектор строк.
Мне интересно, законно ли в первую очередь ожидать, что { ... }
всегда представляет список элементов контейнера при создании временного. Это, кажется, ваше предположение. IMO конструктор с одним аргументом потребности быть объявленным explicit
чтобы избежать нежелания последовательности преобразования или бессмысленные задания, такие как:
vector<int> x = 3;
С другой стороны, для версии с двумя аргументами единственный путь этот конструктор может быть вызван, когда создается временный объект с использованием фигурных скобок, и программист хорошо знает, что он там вводит. Например, мне совершенно ясно, что 10
а также "hello"
не предназначены для представления списка элементов контейнера, потому что 10
это не строка
Если бы я действительно хотел передать вектор из 10 элементов, инициализированных в "hello"
, Я был бы обеспокоен необходимостью писать f(vector(10, "hello"))
вместо того, чтобы просто делать f({10, "hello"})
,
Итак, чтобы подвести итог: в то время как конструктор с одним аргументом должен быть объявлен как explicit
Я считаю, что это не обязательно для значения с двумя аргументами, потому что не все, что находится внутри пары фигурных скобок, следует интерпретировать как список контейнерных элементов.
Хотя, если я опускаю «foo», он не компилируется, и это то, что я ожидаю
когда я передаю пару (составное) значение типа int и строку в функцию, которая хочет
вектор строк.
Нет, вы не передаете пару int и строку, но создаете вектор размером 10 с содержимым строк, например «foo». В этом нет ничего плохого! Я могу представить себе ситуацию, когда было бы полезно создать вектор, содержащий одинаковые строки с самого начала.
это то, что я ожидаю, когда я передаю парное (составное) значение типа int и строки функции, которая хочет вектор строк.
Ну, вот твоя проблема.
{...}
не является «составным значением». Это не список. Он говорит: «инициализировать объект, используя эти значения». Если рассматриваемый объект является агрегатом, он будет использовать агрегатную инициализацию. Если рассматриваемый объект является неагрегированным типом, он выберет конструктор для вызова, основываясь на соответствующих конструкторах типа и различных правилах для braced-init-lists в C ++ 11.
Вы не должны думать о {10, "foo"}
как список двух значений. Это инициализатор, который содержит два значения. Это может быть использовано с std::pair<int, const char *>
, и так далее.
Причина по которой std::vector
конструктор не является явным разрешать эта конструкция. Конструктор с одним аргументом является явным, потому что в противном случае неявные правила преобразования позволили бы это:
std::vector<T> v = 5; //???
Или, что более важно:
void Foo(const std::vector<T> &v);
Foo(5); //???
Мы не хотим, чтобы целые числа были неявно преобразованы в std::vector
s. Однако, когда вы используете инициализатор, более разумно разрешить более широкий диапазон «неявных» преобразований, потому что вы можете видеть {}
синтаксис есть.
В случае с одним аргументом неясно, что означает пользователь. С синтаксисом {} является Понятно, что означает пользователь: для инициализации объекта.
Foo({10, "foo"}); //Initializes the first argument given the values.