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

我找不到这个网站上的第三个示例,而这东西出现在休息室u003CC++>聊天(在与@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 不是唯一适用的类型 char, short, long 和他们 unsigned 版本(可能还有其他一些积分类型)。

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

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

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

其他提示

只是搜索出现 initializer_list.

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

    • Deque
    • Dynarray
    • 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.
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top