为什么 libc++ 的 vector<bool>::const_reference 不是 bool?
Why is libc++'s vector<bool>::const_reference not bool?
第 23.3.7 节 Class vector<bool>
[vector.bool],第 1 段指出:
template <class Allocator> class vector<bool, Allocator> {
public:
// types:
typedef bool const_reference;
...
但是这个程序在使用 libc++ 时编译失败:
#include <vector>
#include <type_traits>
int
main()
{
static_assert(std::is_same<std::vector<bool>::const_reference, bool>{}, "?");
}
此外,我注意到 C++ 标准在本规范中一直保持一致,一直追溯到 C++98。而且我进一步注意到,自从首次引入 libc++ 以来,libc++ 一直没有遵循此规范。
这种不符合的动机是什么?
这个扩展的动机是让 vector<bool>
在引用(const 和其他)方面更像 vector<char>
.
简介
自 1998 年以来,vector<bool>
被嘲笑为 "not quite a container." LWG 96,最早的 LWG 问题之一,引发了争论。 17 年后的今天,vector<bool>
基本保持不变。
This paper 进入了一些具体示例,说明 vector<bool>
的行为与 vector
的所有其他实例有何不同,从而损害了通用代码。然而,同一篇论文详细讨论了如果实施得当,vector<bool>
可以拥有的非常好的性能属性。
总结:vector<bool>
不是一个坏容器。它实际上非常有用。它只是有一个坏名字。
返回const_reference
和 detailed here 一样,vector<bool>
的缺点在于它在通用代码中的行为与其他 vector
实例不同。这是一个具体的例子:
#include <cassert>
#include <vector>
template <class T>
void
test(std::vector<T>& v)
{
using const_ref = typename std::vector<T>::const_reference;
const std::vector<T>& cv = v;
const_ref cr = cv[0];
assert(cr == cv[0]);
v[0] = 1;
assert(true == cv[0]);
assert(cr == cv[0]); // Fires!
}
int
main()
{
std::vector<char> vc(1);
test(vc);
std::vector<bool> vb(1);
test(vb);
}
标准规范表示标记为 // Fires!
的断言将触发,但仅当 test
为 运行 且带有 vector<bool>
时才会触发。当 运行 与 vector<char>
(或除 bool
之外的任何 vector
分配适当的非默认 T
时),测试通过。
libc++ 实现试图将 vector<bool>
在通用代码中表现不同的负面影响降至最低。它为实现这一目标所做的一件事是使 vector<T>::const_reference
成为 代理引用 ,就像指定的 vector<T>::reference
一样,只是您不能通过它进行分配。也就是说,在 libc++ 上,vector<T>::const_reference
本质上是指向 vector
内部位的指针,而不是该位的副本。
在 libc++ 上,vector<char>
和 vector<bool>
都通过了上述 test
。
费用是多少?
缺点是这个扩展是可以检测到的,如问题中所示。然而,很少有程序真正关心这个别名的确切类型,更多的程序关心行为。
What is the motivation for this non-conformance?
为了在通用代码中为 libc++ 客户端提供更好的行为,也许在经过充分的现场测试之后,建议对未来的 C++ 标准进行此扩展,以改善整个 C++ 行业。
这样的提议可能会以新容器的形式出现(例如 bit_vector
),它与今天的 vector<bool>
具有许多相同的 API,但有一些升级,例如const_reference
在这里讨论。随后弃用(并最终删除)vector<bool>
专业化。 bitset
也可以在这个部门进行一些升级,例如添加 const_reference
和一组迭代器。
也就是说,事后看来 bitset
是 vector<bool>
(应该重命名为 bit_vector
-- 或其他),因为 array
是 vector
.无论我们是否将 bool
视为 vector
和 array
.
的 value_type
,这个类比都应该成立
有多个 C++11 和 C++14 功能示例,这些功能最初是作为 libc++ 中的扩展出现的。这就是标准的演变方式。实际 证明 积极 现场经验具有很强的影响力。在更改现有规范(本应如此)时,标准制定者是一群保守派。猜测,即使您确定自己猜对了,对于发展国际公认的标准来说也是一种冒险的策略。
第 23.3.7 节 Class vector<bool>
[vector.bool],第 1 段指出:
template <class Allocator> class vector<bool, Allocator> {
public:
// types:
typedef bool const_reference;
...
但是这个程序在使用 libc++ 时编译失败:
#include <vector>
#include <type_traits>
int
main()
{
static_assert(std::is_same<std::vector<bool>::const_reference, bool>{}, "?");
}
此外,我注意到 C++ 标准在本规范中一直保持一致,一直追溯到 C++98。而且我进一步注意到,自从首次引入 libc++ 以来,libc++ 一直没有遵循此规范。
这种不符合的动机是什么?
这个扩展的动机是让 vector<bool>
在引用(const 和其他)方面更像 vector<char>
.
简介
自 1998 年以来,vector<bool>
被嘲笑为 "not quite a container." LWG 96,最早的 LWG 问题之一,引发了争论。 17 年后的今天,vector<bool>
基本保持不变。
This paper 进入了一些具体示例,说明 vector<bool>
的行为与 vector
的所有其他实例有何不同,从而损害了通用代码。然而,同一篇论文详细讨论了如果实施得当,vector<bool>
可以拥有的非常好的性能属性。
总结:vector<bool>
不是一个坏容器。它实际上非常有用。它只是有一个坏名字。
返回const_reference
和 detailed here 一样,vector<bool>
的缺点在于它在通用代码中的行为与其他 vector
实例不同。这是一个具体的例子:
#include <cassert>
#include <vector>
template <class T>
void
test(std::vector<T>& v)
{
using const_ref = typename std::vector<T>::const_reference;
const std::vector<T>& cv = v;
const_ref cr = cv[0];
assert(cr == cv[0]);
v[0] = 1;
assert(true == cv[0]);
assert(cr == cv[0]); // Fires!
}
int
main()
{
std::vector<char> vc(1);
test(vc);
std::vector<bool> vb(1);
test(vb);
}
标准规范表示标记为 // Fires!
的断言将触发,但仅当 test
为 运行 且带有 vector<bool>
时才会触发。当 运行 与 vector<char>
(或除 bool
之外的任何 vector
分配适当的非默认 T
时),测试通过。
libc++ 实现试图将 vector<bool>
在通用代码中表现不同的负面影响降至最低。它为实现这一目标所做的一件事是使 vector<T>::const_reference
成为 代理引用 ,就像指定的 vector<T>::reference
一样,只是您不能通过它进行分配。也就是说,在 libc++ 上,vector<T>::const_reference
本质上是指向 vector
内部位的指针,而不是该位的副本。
在 libc++ 上,vector<char>
和 vector<bool>
都通过了上述 test
。
费用是多少?
缺点是这个扩展是可以检测到的,如问题中所示。然而,很少有程序真正关心这个别名的确切类型,更多的程序关心行为。
What is the motivation for this non-conformance?
为了在通用代码中为 libc++ 客户端提供更好的行为,也许在经过充分的现场测试之后,建议对未来的 C++ 标准进行此扩展,以改善整个 C++ 行业。
这样的提议可能会以新容器的形式出现(例如 bit_vector
),它与今天的 vector<bool>
具有许多相同的 API,但有一些升级,例如const_reference
在这里讨论。随后弃用(并最终删除)vector<bool>
专业化。 bitset
也可以在这个部门进行一些升级,例如添加 const_reference
和一组迭代器。
也就是说,事后看来 bitset
是 vector<bool>
(应该重命名为 bit_vector
-- 或其他),因为 array
是 vector
.无论我们是否将 bool
视为 vector
和 array
.
value_type
,这个类比都应该成立
有多个 C++11 和 C++14 功能示例,这些功能最初是作为 libc++ 中的扩展出现的。这就是标准的演变方式。实际 证明 积极 现场经验具有很强的影响力。在更改现有规范(本应如此)时,标准制定者是一群保守派。猜测,即使您确定自己猜对了,对于发展国际公认的标准来说也是一种冒险的策略。