Если я напишу это
std::vector<std::string> v{"one","two","three"};
Какой тип выведен для ассоциированного std::initializer_list
шаблон?
Другими словами, когда char *
строковые литералы преобразуются в std::string
?
Лучше объявить это как
std::vector<std::string> v{std::string("one"),
std::string("two"),
std::string("three")};
чтобы избежать проблем, связанных с механизмом определения типа используемых шаблонов?
Я буду придерживаться той же оптимизации с этим?
Обновить: Чтобы ответить на ваш вопрос о типе вывод:
Конструктор списка инициализатора vector<string>
занимает initializer_list<string>
, Это не шаблонно, поэтому ничего не происходит с точки зрения вывода типа.
Тем не менее, тип преобразование и правила разрешения перегрузки, применяемые здесь, представляют некоторый интерес, поэтому я оставлю свой первоначальный ответ в силе, так как вы уже приняли его:
Оригинальный ответ:
Сначала компилятор видит только список инициализаторов {"one","two","three"}
, который является только списком инициализаторов, но еще не является объектом типа std::initializer_list
,
Затем он пытается найти подходящего конструктора vector<string>
чтобы соответствовать этому списку.
Как это сделать, это довольно сложный процесс, вам лучше всего посмотреть в самом стандарте, если вы заинтересованы в точном процессе.
Поэтому компилятор решает создать фактический объект std::initializer_list<string>
от список инициализаторов, поскольку неявное преобразование из char*
к std::string
s делает это возможным.
Еще один, может быть, более интересный пример:
std::vector<long> vl1{3};
std::vector<string> vs1{3};
std::vector<string> vs2{0};
Что они делают?
Первая строка относительно проста. список инициализаторов {3}
может быть преобразован в std::initializer_list<long>
аналогично {"onm", "two", "three"}
Пример выше, так что вы получите вектор с одним элементом, который имеет значение 3.
Вторая строка отличается. Он строит вектор из 3 пустых строк. Зачем? Потому что список инициализаторов {3}
ни в коем случае не может быть преобразован в std::initializer_list<string>
так что «нормальный» конструктор std::vector<T>::vector(size_t, T = T())
включается и дает три строки по умолчанию.
Ну, этот должен быть примерно таким же, как второй, верно? Другими словами, он должен давать пустой вектор с нулевыми строками по умолчанию. НЕПРАВИЛЬНО!. 0
может рассматриваться как константа нулевого указателя, и проверяет std::initializer_list<string>
, Только на этот раз единственная строка в этом списке создается нулевым указателем, что недопустимо, поэтому вы получаете исключение.
Вывод типа отсутствует, поскольку вектор предоставляет только полностью специализированный конструктор со списком инициализаторов. Мы могли бы добавить шаблонную косвенность, чтобы играть с выводом типа. Пример ниже показывает, что std::initializer_list<const char*>
является недопустимым аргументом для векторного конструктора.
#include <string>
#include <vector>
std::string operator"" _s( const char* s, size_t sz ) { return {s, s+sz}; }
template<typename T>
std::vector<std::string> make_vector( std::initializer_list<T> il ) {
return {il};
}
int main() {
auto compile = make_vector<std::string>( { "uie","uieui","ueueuieuie" } );
auto compile_too = make_vector<std::string>( { "uie"_s, "uieui", "ueueuieuie" } );
//auto do_not_compile = make_vector( { "uie","uieui","ueueuieuie" } );
}
От http://en.cppreference.com/w/cpp/language/string_literal:
Тип строкового литерала без префикса
const char[]
Таким образом, дела идут так:
#include <iostream>
#include <initializer_list>
#include <vector>
#include <typeinfo>
#include <type_traits>
using namespace std;
int main() {
std::cout << std::boolalpha;
std::initializer_list<char*> v = {"one","two","three"}; // Takes string literal pointers (char*)
auto var = v.begin();
char *myvar;
cout << (typeid(decltype(*var)) == typeid(decltype(myvar))); // true
std::string ea = "hello";
std::initializer_list<std::string> v2 = {"one","two","three"}; // Constructs 3 std::string objects
auto var2 = v2.begin();
cout << (typeid(decltype(*var2)) == typeid(decltype(ea))); // true
std::vector<std::string> vec(v2);
return 0;
}