列表初始化是否为隐式转换
Is list-initialization an implicit conversion?
#include <iostream>
#include <string>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <vector>
class Base{
public:
virtual ~Base() {}
};
class Derived: public Base { };
int main(){
int arr[10];
Derived d;
Base *p = &d;
std::map<std::type_index, std::string> proper_name = {
{typeid(int), "int"}, {typeid(double), "double"}, {typeid(float), "float"}, {typeid(char), "char"},
{typeid(Base), "Base"}, {typeid(Derived), "Derived"}, {typeid(std::string), "String"},
{typeid(int[10]), "Ten int Array"}, {typeid(p), "Base Pointer"}};
}
我试图理解此列表初始化中发生的隐式转换。从 N3337 的13.3.1.7
:
当非聚合类类型 T 的对象进行列表初始化 (8.5.4) 时,重载解析会在两个阶段选择构造函数:
最初,候选函数是类 T 的初始值设定项列表构造函数 (8.5.4),参数列表由作为单个参数的初始值设定项列表组成。
如果未找到可行的初始值设定项列表构造函数,则再次执行重载解析,其中候选函数是类 T 的所有构造函数,参数列表由初始值设定项列表的元素组成。
8.5.4
:
构造函数是初始值设定项列表构造函数,如果它的第一个参数是类型
std::initializer_list<E>
或引用某些类型E
的可能符合 cv 的std::initializer_list<E>
,并且没有其他参数,或者所有其他参数都有默认参数
因此,以下 std::map
的构造函数列表指示
map (initializer_list<value_type> il,
const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type())
;
是候选函数,value_type
在本例中是pair<const type_index, std::string>
。最后来自13.3.3.1.5
:
如果参数类型是
std::initializer_list<X>
或"X
数组"135 并且初始值设定项列表的所有元素都可以隐式转换为X
,则隐式转换序列是将列表中的元素转换为X
所需的最差转换。
因此,只要大括号列表的元素隐式转换为 pair<const type_index, std::string>
,它就是有效的转换。但这些元素本身也是大括号列表。 Pair
不接受初始值设定项列表构造函数,从这里看来,来自大括号初始化列表的复制初始化使用13.3.1.7
的第二部分来构造对象。所以以下内容:
pair<const type_index, std::string> p = {typeid(int), "int"}
成为:
pair<const type_index, std::string> p(typeid(int), "int")
但这算不算隐式转换?如何将双参数构造函数的使用视为隐式转换?标准对此有何评论?
你的结论是
pair<const type_index, std::string> p = {typeid(int), "int"};
成为
pair<const type_index, std::string> p(typeid(int), "int");
不准确,因为第一条语句是复制列表初始化,而第二条语句是直接初始化。这两者是相同的,只是如果选择了explicit
构造函数,则复制列表初始化的格式不正确(并且前者不允许缩小转换范围)。
因此,如果所讨论的pair
构造函数定义为
template<class U1, class U2>
explicit constexpr pair(U1&& x, U2&& y);
直接初始化仍将成功,但复制列表初始化将失败。引用您引用的[over.match.list]部分的正下方
在复制列表初始化中,如果选择了
explicit
构造函数,则初始化格式不正确。
除此之外,你所说的其他一切都是正确的。pair
构造函数是隐式转换,因为构造函数不是explicit
的,并且根据 [over.match.list] 的第二个项目符号考虑重载解析,因为pair
没有初始值设定项列表构造函数。
- 复制列表初始化的隐式转换的等级是多少
- C++转换参数初始化问题
- 不能将复制初始化与隐式转换的多个步骤一起使用
- 需要帮助在 c++ 中将字符串转换为字符 ----错误 "const char *" 类型的值不能用于初始化 "char" 类型的实体
- 虚拟成员函数的定义是否强制在同一转换单元中动态初始化静态数据成员?
- 是否可以将已经初始化的变量转换为 void*?
- C++列表初始化允许多个用户定义的转换
- 为什么 gcc 警告只针对统一初始化缩小转换范围?
- 无法在初始化时将"日期"转换为"int"作为错误
- 常量转发引用给出错误 C2440:"正在初始化":无法从"常量标准::字符串"转换为"常量标准::字符串 &&"
- 统一初始化是隐式发生的,即使 int 强制转换运算符是使用 explicit 关键字声明的.原因是什么?
- 使用转换函数直接初始化
- 正在初始化:无法从'_Ty*'转换为 List<int,std::分配器<节点<T>>>:节点*
- 警告 C4267"正在初始化":从'size_t'转换为"DWORD",可能会丢失数据
- 通过用户定义的转换初始化引用
- 在C++中初始化bool32_t对象时,我们需要强制转换它还是它会自动识别它?
- 复制初始化 - 从 'int' 类型转换为非标量类型
- 用于初始化结构的 void 指针强制转换
- 错误 C2440:"正在初始化":无法从"初始值设定项列表"转换为"std::vector<char *,std::分配器<_Ty>>
- 转换初始化器列表