布尔数组没有 class 模板专业化?

No class template specialization for array of bool?

根据 https://en.cppreference.com/std::vector<bool> 有一个 class 模板特化,而 std::array<bool, N> 没有。没有提供的原因有哪些?

这是一道关于C++演进史的题。事后看来,一个可能的解释是:

std::vector<bool> 是一个错误。 std::vector<bool>std::vector<T> 非常不同,这是一个主要的烦恼。使用 vectors 的通用代码通常需要 std::vector<bool> 的特殊情况。并且用户通常不得不应用奇怪的解决方法,例如使用 std::vector<char> 代替 std::vector<bool>。现在我们不能在不破坏大量现有代码的情况下返回。就我们现在所知,也许 std::vector<bool> 永远不会变成 C++。

std::array 仅在 C++11 中添加。没有理由再犯同样的错误。

引入 std::vector 时,bool 的专业化被认为是个好主意。基本上,那时候一般的电脑都有4MB的内存,所以节省电脑内存是相当重要的。现在我们只是说“内存很便宜”(引自 Uncle Bob)。

后来发现这种专业化带来的问题多于它的价值。

问题在于,与常规的老式 C 数组相比,此类向量的其中一个元素的地址是一个复杂的对象(它必须存储有关哪个位保存哪个值的信息)bool a[].

既然要保持兼容性,这个专精不能丢,但是基于那次教训,同样的做法没有应用到std::array

另一个原因是std::array应该是一个C数组包装器,所以它必须尽可能类似于bool a[N],并且在使用时必须产生相同的机器代码。

最后一件事,正如 Cody Gray 在 中指出的那样,std::bitset 是一个恒定大小的位数组,因此此类功能已经可用(并且可以在需要时使用)。

早在 1994 年就引入了 std::vector<bool> 专业化,根据 lib.vector.bool of WG21/N0545(1) [强调 我的]:

23.1.6 Class vector<bool> [lib.vector.bool]

To optimize space allocation, a specialization for bool is provided: [...]

有动力优化 space 分配,这是当时稀缺的资源。

回想起来,这是一个非常糟糕的主意,随着计算机硬件可用 space 的快速增长,最初的动机变得毫无意义。

另一方面,

std::array 是在 C++11 中引入的,例如auto 类型推导,这种机制突出了 std::vector<bool> 专业化的另一个问题。当然,库规范编写者在设计 std::array.

时不会重蹈 std::vector<bool> 的覆辙

例如,以下片段

#include <type_traits>
#include <vector>

int main() {
    std::vector<bool> v{false, false, true, true};
    auto bool_value = v[1];
    static_assert(std::is_same_v<decltype(bool_value), bool>, "");  // Error!
}   

失败,错误消息是 bool_value 不是 bool 类型,而是加密类型(实现定义)

error: static_assert failed due to requirement
'std::is_same_v<
    std::__1::__bit_reference<
        std::__1::vector<bool, std::__1::allocator<bool>>, true>, 
    bool>' ""

(1) 信息系统拟议国际标准草案的工作文件——编程语言 C++。

bool 专门化 std::vector 的最初动机是优化内存使用。

然而,这是一个坏主意,因为这种专业化的行为与通常的行为不同std::vector(参见下面的示例)。

此错误在后来的 C++11 std::array

中没有重现
#include <array>
#include <vector>

int main()
{
  std::vector<int> i_v(4);
  int i_a = *&i_v[3]; // ok

  std::vector<bool> v(4);
  bool a = *&v[3]; // Compile-time error

  std::array<bool,4> w;
  bool b = *&w[3]; // ok
}