14

自 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)。

问题:标准库中是否还有更多示例,其中将()样式构造函数转换为{}样式,由初始化列表构造函数贪婪匹配?

4

2 回答 2

5

我假设,在你的例子中std::vector<int>std::string你的意思是还包括其他容器,例如,,std::list<int>std::deque<int>,它们显然有同样的问题,因为std::vector<int>。同样, theint不是唯一的类型,因为它也适用于,char及其版本(也可能是其他一些整数类型)。shortlongunsigned

我认为也有,std::valarray<T>但我不确定是否T允许为整数类型。实际上,我认为这些具有不同的语义:

std::valarray<double>(0.0, 3);
std::valarray<double>{0.0, 3};

还有一些其他标准 C++ 类模板采用std::initializer_list<T>as 参数,但我认为其中任何一个都没有重载的构造函数,当使用括号而不是大括号时会使用该构造函数。

于 2013-11-07T22:43:24.090 回答
4

只是搜索initializer_list.

  • 所有序列,它们都有像向量一样的构造函数:

    • 双端队列
    • 动态阵列
    • forward_list
    • 列表
    • 向量
  • 值数组

  • 基本字符串

  • 无序集合,有一个构造函数,它接受一个整数来确定初始桶数。

    • 无序集
    • unordered_multiset

我想这就是全部。

#include <unordered_set>
#include <iostream>

int main() {
    std::unordered_set<int> f (3);
    std::unordered_set<int> g {3};
    std::cout << f.size() << "/" << g.size() << std::endl; // prints 0/1.
}
于 2013-11-07T22:59:03.573 回答