Почему конструкторы с несколькими аргументами вектора, принимающие параметры конструкции, не помечены как «явные»?

Я заметил следующие векторные конструкторы в стандартной библиотеке 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 и строку в функцию, которая хочет вектор строк.

9

Решение

Мне интересно, законно ли в первую очередь ожидать, что { ... } всегда представляет список элементов контейнера при создании временного. Это, кажется, ваше предположение. IMO конструктор с одним аргументом потребности быть объявленным explicit чтобы избежать нежелания последовательности преобразования или бессмысленные задания, такие как:

vector<int> x = 3;

С другой стороны, для версии с двумя аргументами единственный путь этот конструктор может быть вызван, когда создается временный объект с использованием фигурных скобок, и программист хорошо знает, что он там вводит. Например, мне совершенно ясно, что 10 а также "hello" не предназначены для представления списка элементов контейнера, потому что 10 это не строка

Если бы я действительно хотел передать вектор из 10 элементов, инициализированных в "hello", Я был бы обеспокоен необходимостью писать f(vector(10, "hello")) вместо того, чтобы просто делать f({10, "hello"}),

Итак, чтобы подвести итог: в то время как конструктор с одним аргументом должен быть объявлен как explicitЯ считаю, что это не обязательно для значения с двумя аргументами, потому что не все, что находится внутри пары фигурных скобок, следует интерпретировать как список контейнерных элементов.

3

Другие решения

Хотя, если я опускаю «foo», он не компилируется, и это то, что я ожидаю
когда я передаю пару (составное) значение типа int и строку в функцию, которая хочет
вектор строк.

Нет, вы не передаете пару int и строку, но создаете вектор размером 10 с содержимым строк, например «foo». В этом нет ничего плохого! Я могу представить себе ситуацию, когда было бы полезно создать вектор, содержащий одинаковые строки с самого начала.

1

это то, что я ожидаю, когда я передаю парное (составное) значение типа 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::vectors. Однако, когда вы используете инициализатор, более разумно разрешить более широкий диапазон «неявных» преобразований, потому что вы можете видеть {} синтаксис есть.

В случае с одним аргументом неясно, что означает пользователь. С синтаксисом {} является Понятно, что означает пользователь: для инициализации объекта.

Foo({10, "foo"}); //Initializes the first argument given the values.
0
По вопросам рекламы [email protected]