布尔数组没有 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>
非常不同,这是一个主要的烦恼。使用 vector
s 的通用代码通常需要 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
}
根据 https://en.cppreference.com/,std::vector<bool>
有一个 class 模板特化,而 std::array<bool, N>
没有。没有提供的原因有哪些?
这是一道关于C++演进史的题。事后看来,一个可能的解释是:
std::vector<bool>
是一个错误。 std::vector<bool>
与 std::vector<T>
非常不同,这是一个主要的烦恼。使用 vector
s 的通用代码通常需要 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
}