哪些贪婪的初始化列表示例潜伏在标准库中?

时间:2013-11-07 22:25:55

标签: c++ c++11 initializer-list list-initialization

从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'
}

我在这个网站上找不到第三个例子,而这个问题出现在休息室&lt; C ++&gt;聊天(与@rightfold,@ Abyx和@JerryCoffin讨论),有点令人惊讶的是,将std::string构造函数转换为计数和字符使用{}而不是(),将其含义从n个字符副本更改为n个字符(通常来自ASCII表),后跟另一个字符。

这通常不会限制缩小转换,因为65是一个常量表达式,可以表示为char,并在转换回int时保留其原始值(§8.5.4/ 7,bullet 4) )(感谢@JerryCoffin)。

问题:标准库中是否有更多示例将()样式构造函数转换为{}样式,并且初始化列表构造函数会贪婪地匹配?< / p>

2 个答案:

答案 0 :(得分:4)

我假设您的std::vector<int>std::string示例也涵盖了其他容器,例如std::list<int>std::deque<int>等具有相同容器的容器问题显然是std::vector<int>。同样,int不是唯一的类型,因为它也适用于charshortlong及其unsigned版本(可能还有其他几个整体)类型,也是。)

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

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

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

答案 1 :(得分:3)

只是搜索initializer_list

的出现
  • 所有序列,它们都具有类似于vector的构造函数:

    • deque
    • 的DynArray
    • 修饰符Modifiers
    • 列表
    • 矢量
  • 的valarray

  • basic_string的

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

    • unordered_set
    • 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.
}