列表初始化是隐式转换吗?
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
:
When objects of non-aggregate class type T are list-initialized (8.5.4), overload resolution selects the constructor in two phases:
Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of the initializer list as a single argument.
If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.
8.5.4
:
A constructor is an initializer-list constructor if its first parameter is of type std::initializer_list<E>
or reference to possibly cv-qualified std::initializer_list<E>
for some type E
, and either there are no other parameters or else all other parameters have default arguments
所以 the following 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
:
If the parameter type is std::initializer_list<X>
or “array of X
”135 and all the elements of the initializer list can be implicitly converted to X
, the implicit conversion sequence is the worst conversion necessary to convert an element of the list to X
.
因此,只要花括号列表的元素隐式转换为 pair<const type_index, std::string>
,它就是一个有效的转换。但这些元素本身也是花括号列表。 Pair
不采用初始化列表构造函数,from here 似乎来自花括号初始化列表的复制初始化使用 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");
不准确,因为第一个语句是 copy-list-initialization,而第二个语句是 direct-initialization。两者是相同的,除了 copy-list-initialization 是 ill-formed 如果选择 explicit
构造函数(并且前者不允许缩小转换)。
因此,如果有问题的 pair
构造函数被定义为
template<class U1, class U2>
explicit constexpr pair(U1&& x, U2&& y);
direct-initialization 仍然会成功,但 copy-list-initialization 会失败。从 [over.match.list] 部分的正下方引用你引用的
In copy-list-initialization, if an explicit
constructor is chosen, the initialization is ill-formed.
除此之外,你说的其他都是正确的。 pair
构造函数是隐式转换,因为构造函数不是 explicit
并且根据 [over.match.list] 的第二个项目符号考虑重载决议因为 pair
没有初始化列表构造函数。
#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
:
When objects of non-aggregate class type T are list-initialized (8.5.4), overload resolution selects the constructor in two phases:
Initially, the candidate functions are the initializer-list constructors (8.5.4) of the class T and the argument list consists of the initializer list as a single argument.
If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list.
8.5.4
:
A constructor is an initializer-list constructor if its first parameter is of type
std::initializer_list<E>
or reference to possibly cv-qualifiedstd::initializer_list<E>
for some typeE
, and either there are no other parameters or else all other parameters have default arguments
所以 the following 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
:
If the parameter type is
std::initializer_list<X>
or “array ofX
”135 and all the elements of the initializer list can be implicitly converted toX
, the implicit conversion sequence is the worst conversion necessary to convert an element of the list toX
.
因此,只要花括号列表的元素隐式转换为 pair<const type_index, std::string>
,它就是一个有效的转换。但这些元素本身也是花括号列表。 Pair
不采用初始化列表构造函数,from here 似乎来自花括号初始化列表的复制初始化使用 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");
不准确,因为第一个语句是 copy-list-initialization,而第二个语句是 direct-initialization。两者是相同的,除了 copy-list-initialization 是 ill-formed 如果选择 explicit
构造函数(并且前者不允许缩小转换)。
因此,如果有问题的 pair
构造函数被定义为
template<class U1, class U2>
explicit constexpr pair(U1&& x, U2&& y);
direct-initialization 仍然会成功,但 copy-list-initialization 会失败。从 [over.match.list] 部分的正下方引用你引用的
In copy-list-initialization, if an
explicit
constructor is chosen, the initialization is ill-formed.
除此之外,你说的其他都是正确的。 pair
构造函数是隐式转换,因为构造函数不是 explicit
并且根据 [over.match.list] 的第二个项目符号考虑重载决议因为 pair
没有初始化列表构造函数。