为什么我们需要一个私有构造函数来定义std::initializer_list?

12
标准C++程序设计语言中,std::initializer_list的建议实现是简单的。这里的“简单”指的是没有什么奇怪的东西。
但在编译器实现std::initializer_list时会变得复杂,例如,GCC拥有一个私有构造函数用于std::initializer_list,并在其上方有一条注释,其中说:'编译器可以调用私有构造函数。'。 在这里,eerorika回答说:std::initializer_list是特殊的。因此,我查找了编译器源代码中的相关信息:

Clang:

GCC:

我不明白为什么我们需要有一个特殊的私有构造函数?我之前遇到过这个问题,当时我想把std::vector<T>转换成std::initializer_list<T>


3
在我看来,这是为了防止人们不正确地使用std::initializer_list。你真的应该只通过复制一个列表或者隐式从{list, of, values, ...}创建一个std::initializer_list。如果一个类型可以从std::initializer_list构造,它也应该有一个接受迭代器范围的构造函数,以便从任何值的“列表”中构造。 - NathanOliver
更加注重正确性和安全性。std::initializer_list 用于模拟 { an, intializer, list, ...}。它由编译器为我们创建的临时数组支持,然后在销毁 std::initializer_list 对象时负责销毁该数组。如果您可以访问 initializer_list(const_iterator __a, size_type __l) 构造函数,则可以使其指向不是初始化列表的内容,并且内存不受编译器控制。 - NathanOliver
没错。std::initializer_list 是初始化列表的具体化,它不应该存在于其他情况下。特别是你不应该从代码中构造一个来统一两个用例。 - Sneftel
3
既然库已经有了命名空间,为什么要添加新的关键字并可能破坏现有的代码? - StoryTeller - Unslander Monica
1
顺便提一下,也要记住标准头文件不需要是文件(甚至不需要是常规头文件)。 - Jarod42
显示剩余4条评论
1个回答

5

std::initializer_list 是实际初始化列表的具象化,其构造函数是 private 的,仅为确保没有人能够调用它(当然除了编译器),从而防止人们错误地使用 std::initializer_list

正如 StoryTeller 所提到的: 有一个 gsl::span (或在 C++20 中的 std::span)以用于连续范围抽象目的。但看起来你试图通过 std::initializer_list 进行(滥用)。
(你不能这样做,因为那只是用于支持 {...} 初始化的辅助类型。)


从评论中得知:

......它不能直接由编译器处理吗?我的意思是说,像它专属的新关键字之类的东西?

嗯,新关键字可能会破坏现有代码,但 std 命名空间是一个相当安全的位置(用于防止冲突)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接