为什么使用统一的初始化程序语法会导致与“旧的”初始化行为不同的行为?样式()? [英] Why does using uniform initializer syntax result in different behavior to the "old" style ()?
问题描述
如果尝试对 std :: set
使用统一的初始化程序,则会得到不同的结果。
I get different results if I try to use a uniform initializer for std::set
.
示例:
int main()
{
std::array a {1,2,3,4};
std::set<int> s1 {a.begin(), a.end()};
std::set s2 {a.begin(), a.end()};
std::set s3 (a.begin(), a.end());
for(auto& i: s1) { std::cout << i << "\n"; }
std::cout << "####" << std::endl;
for(auto& i: s2) { std::cout << i << "\n"; }
std::cout << "####" << std::endl;
for(auto& i: s3) { std::cout << i << "\n"; }
}
结果是:
1
2
3
4
####
0x7ffecf9d12e0
0x7ffecf9d12f0
####
1
2
3
4
这似乎与扣除指南有关,如果与 {}
或()$ c $一起使用,则对它们的评估会有所不同c>语法。
This seems to be related to "deduction guides", which are evaluated differently if used with {}
or ()
syntax.
推荐答案
简短答案
对于 s2
,使用大括号语法,而 {a.begin(),a.end()}
被视为< std :: array< int> :: iterator
的code> initializer_list 。因此, s2
是一组迭代器。
Short answer
For s2
, brace syntax is used, and {a.begin(), a.end()}
is considered to be an initializer_list
of std::array<int>::iterator
s. Therefore, s2
is a set of iterators.
对于 s3
,使用括号语法,并选择迭代器构造函数。 s3
是一组 int
s,并从范围内初始化。 (),a.end())
。
For s3
, parentheses syntax is used, and the iterator constructor is selected. s3
is a set of int
s, and is initialized from the range [a.begin(), a.end())
.
每 [set.overview] ,我们这里有两个相关的推导指南:
Per [set.overview], we have two deduction guides relevant here:
template<class InputIterator,
class Compare = less<typename iterator_traits<InputIterator>::value_type>,
class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
set(InputIterator, InputIterator,
Compare = Compare(), Allocator = Allocator())
-> set<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>;
和
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
set(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
-> set<Key, Compare, Allocator>;
每< a href = https://timsong-cpp.github.io/cppwp/n4659/over.match.class.deduct#1 rel = noreferrer> [over.match.class.deduct] / 1 :
形成了一组函数和功能模板,包括:
A set of functions and function templates is formed comprising:
-
[...]
[...]
(1.4)对于每个推导指南,具有以下属性的函数或函数模板:
(1.4) For each deduction-guide, a function or function template with the following properties:
-
模板参数(如果有)和函数参数是扣除指南。
返回类型是推导指南中的 simple-template-id 。
在这种情况下,前述推导指南的综合函数和函数模板分别为
In this case, the synthesized functions and function templates for the aforementioned deduction guides are, respectively,
template<class InputIterator,
class Compare = less<typename iterator_traits<InputIterator>::value_type>,
class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
auto __func1(InputIterator, InputIterator,
Compare = Compare(), Allocator = Allocator())
-> set<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>;
和
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
auto __func2(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
-> set<Key, Compare, Allocator>;
(我用双下划线表示这些名称是合成的,否则无法访问。)
(I used double underscores to signify that these names are synthesized, and are not otherwise accessible.)
每个 [over.match.class.deduct] / 2 :
初始化和重载解析按照
[dcl.init]和[over.match.ctor],[over.match.copy]或
[over.match.list]中的描述进行(如适合于假设类类型的对象执行的初始化
的类型),其中出于以下目的,选择的
函数和函数模板被视为该类类型的
构造函数形成一个重载
集,并由执行类
模板自变量推断的上下文提供初始化程序。如果函数或函数
模板是从构造函数或 deduction-guide 生成
声明为<$ c $的函数或函数
模板,则认为每个这样的概念性
构造函数都是显式的c>明确。所有这些概念性构造函数都被视为
是假设类类型的公共成员。
Initialization and overload resolution are performed as described in [dcl.init] and [over.match.ctor], [over.match.copy], or [over.match.list] (as appropriate for the type of initialization performed) for an object of a hypothetical class type, where the selected functions and function templates are considered to be the constructors of that class type for the purpose of forming an overload set, and the initializer is provided by the context in which class template argument deduction was performed. Each such notional constructor is considered to be explicit if the function or function template was generated from a constructor or deduction-guide that was declared
explicit
. All such notional constructors are considered to be public members of the hypothetical class type.
假设类类型如下:
class __hypothetical {
public:
// ...
// #1
template<class InputIterator,
class Compare = less<typename iterator_traits<InputIterator>::value_type>,
class Allocator = allocator<typename iterator_traits<InputIterator>::value_type>>
__hypothetical(InputIterator, InputIterator,
Compare = Compare(), Allocator = Allocator())
-> set<typename iterator_traits<InputIterator>::value_type, Compare, Allocator>;
// #2
template<class Key, class Compare = less<Key>, class Allocator = allocator<Key>>
__hypothetical(initializer_list<Key>, Compare = Compare(), Allocator = Allocator())
-> set<Key, Compare, Allocator>;
// ...
};
用于声明 s2
,
std::set s2 {a.begin(), a.end()};
重载解析的执行就像在
__hypothetical __hyp{a.begin(), a.end()}; // braces
因此, [over.match.list] 进来。
[...]重载决议分两个阶段选择构造函数:
[...] overload resolution selects the constructor in two phases:
-
最初,候选函数是<
T
类的em> initializer-list构造函数([dcl.init.list])和参数列表
包含以下初始化列表:
Initially, the candidate functions are the initializer-list constructors ([dcl.init.list]) of the class
T
and the argument list consists of the initializer list as a single argument.
[...]
构造函数#2是初始化列表构造器。函数模板参数推导给出
Constructor #2 is an initializer-list constructor. Function template argument deduction gives
Key = std::array<int>::iterator
所以 s2
的推导类型为
std::set<std::array<int>::iterator>
s2
的声明等效于
std::set<std::array<int>::iterator> s2 {a.begin(), a.end()};
因此, s2
是一组迭代器其中包含两个元素: a.begin()
和 a.end()
。在您的情况下, std :: array< int> :: iterator
可能是 int * 和
a.begin()
和 a.end()
恰好被序列化为 0x7ffecf9d12e0
和 0x7ffecf9d12f0
。
Therefore, s2
is a set of iterators that consists of two elements: a.begin()
and a.end()
. In your case, std::array<int>::iterator
is probably int*
, and a.begin()
and a.end()
happen to be serialized as 0x7ffecf9d12e0
and 0x7ffecf9d12f0
, respectively.
对于 s3
,执行重载解析就像在
For s3
, overload resolution is performed as if in
__hypothetical __hyp(a.begin(), a.end()); // parentheses
这是直接初始化,并且在 [pver.match.ctor] 。 initializer_list
构造函数无关紧要,而是选择了构造函数#1。函数模板参数推导给出
That's direct-initialization, and is under the scope of [pver.match.ctor]. The initializer_list
constructor is irrelevant, and the Constructor #1 is selected instead. Function template argument deduction gives
InputIterator = std::array<int>::iterator
所以 s3
的推导类型为
set<iterator_traits<std::array<int>::iterator>::value_type>
哪个是 set< int>
。因此, s3
的声明等效于
Which is set<int>
. Therefore, the declaration of s3
is equivalent to
std::set<int> s3 (a.begin(), a.end());
s3
是一组<$ c从范围 [a.begin(),a.end())
初始化的$ c> int s—四个元素 1、2、3、4
,用于解释输出。
s3
is a set of int
s that is initialized from the range [a.begin(), a.end())
— four elements 1, 2, 3, 4
, which explains the output.
这篇关于为什么使用统一的初始化程序语法会导致与“旧的”初始化行为不同的行为?样式()?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!