自C++11起,标准库容器和
std::string
具有接受初始化列表的构造函数。此构造函数优先于其他构造函数(即使在其他“最佳匹配”标准被忽略的情况下,正如@JohannesSchaub-litb在评论中指出的那样)。这导致将所有括号形式()
的构造函数转换为它们的花括号版本{}
时出现了一些众所周知的陷阱。#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <string>
void print(std::vector<int> const& v)
{
std::copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, ","));
std::cout << "\n";
}
void print(std::string const& s)
{
std::cout << s << "\n";
}
int main()
{
// well-known
print(std::vector<int>{ 11, 22 }); // 11, 22, not 11 copies of 22
print(std::vector<int>{ 11 }); // 11, not 11 copies of 0
// more surprising
print(std::string{ 65, 'C' }); // AC, not 65 copies of 'C'
}
在这个网站上我找不到第三个例子,这件事在Lounge<C++>聊天中被提出(与@rightfold、@Abyx和@JerryCoffin讨论)。有些令人惊讶的是,将取一个计数和一个字符的std::string
构造函数转换为使用{}
而不是()
,会将其含义从字符的n
个副本改变为第n
个字符(通常来自ASCII表)后跟另一个字符。
这不符合通常的花括号禁止缩小转换规则,因为65是一个常量表达式,可以表示为char,并且在转换回int时将保留其原始值(§8.5.4/7,第4个项目)(感谢@JerryCoffin)。
问题: 在标准库中是否存在更多例子,其中将()
样式的构造函数转换为{}
样式,会被初始化列表构造函数贪心地匹配?
string
、valarray
、所有容器、min
/max
/minmax
、正则表达式、一些随机分布和seed_seq
。 - Kerrek SBinitializer_list<T>
;很少有情况下你会使用编译时已知数量的对象来构造容器。在我看来,它所做的一切都是引入一些愚蠢的边缘情况。 - Simple