标准库中潜伏着哪些贪婪的初始值设定项列表示例



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

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

通常禁止

缩小转换范围,这并没有被捕获,因为 65 是一个常量表达式,可以表示为 char,并且在转换回 int 时将保留其原始值(§8.5.4/7,项目符号 4)(感谢 @JerryCoffin)。

问题:标准库中是否潜伏着更多示例,其中将()样式构造函数转换为{}样式,与初始值设定项列表构造函数贪婪地匹配?

我假设,通过您的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>作为参数,但我认为其中任何一个都没有重载的构造函数,当使用括号而不是大括号时会使用。

只是搜索initializer_list的出现。

  • 所有序列,它们都具有类似于向量的构造函数:

    • 德克
    • 戴琳阵列
    • forward_list
    • 列表
    • 向量
  • 瓦拉雷

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

最新更新