如果我写这个
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")};
避免与所涉及模板的类型推导机制相关的问题? 我会对此保持相同的优化吗?
答案 0 :(得分:7)
更新:要回答有关推理类型的问题:
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())
会启动并提供三个默认构造的字符串
那么这个应该与第二个大致相同,对吗?它应该给出一个空向量,换句话说,使用零默认构造的字符串。的 WRONG!即可。可以将0
视为空指针常量,并验证std::initializer_list<string>
。只有这次该列表中的单个字符串由nullpointer构造,这是不允许的,所以你得到一个例外。
答案 1 :(得分:3)
没有类型推断,因为向量仅提供具有初始化列表的完全专用的构造函数。我们可以添加模板间接来玩类型推导。下面的示例显示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" } );
}
答案 2 :(得分:2)
来自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;
}