标准库中的类模板 std::bitset<N>
有一个构造函数(C++11及以上版本,在C++11之前使用 unsigned long
参数)
constexpr bitset(unsigned long long) noexcept
与许多最佳实践指南相反,这个单参数构造函数没有标记为
explicit
。这背后的理由是什么?标准库中的类模板 std::bitset<N>
有一个构造函数(C++11及以上版本,在C++11之前使用 unsigned long
参数)
constexpr bitset(unsigned long long) noexcept
explicit
。这背后的理由是什么?对于一个显式
构造函数的主要反对意见是,从无符号整数进行复制初始化将不再起作用。
constexpr auto N = 64;
std::bitset<N> b(0xDEADC0DE); // OK, direct initialization
std::bitset<N> b = 0xDEADC0DE; // ERROR, copy initialization cannot use explicit constructors
由于std::bitset<N>
旨在作为unsigned int
的泛化,因此构造函数可能被设计成隐式的,以便基于原始unsigned int
的现有C风格位操作代码进行适应。使构造函数变为explicit
会破坏许多现有的代码(现在添加它也将同样破坏许多现有的代码)。
更新:进行了一些标准考古学研究,我发现1995年1月提出了N0624,建议在预标准库草案中向所有单参数构造函数添加当时全新的关键字explicit
。这在1995年3月(奥斯汀)的会议上进行了投票。如N0661所记录的那样,bitset
的unsigned long
构造函数没有被设置为explicit
(一致的投票结果,但没有动机)。
然而,尽管bitset
可以轻松从unsigned long
初始化,但除此之外,混合模式下的集合操作(&
、|
或^
)是不完整的:
constexpr auto N = 512;
std::bitset<N> b = 0xDEADC0DE; // OK
std::bitset<N> c = b & 0xFFFF; // ERROR, cannot deduce template arguments for rhs
// @ from { &, |, ^ }
template<std::size_t N>
bitset<N> operator@(unsigned long long lhs, const bitset<N>& rhs)
template<std::size_t N>
bitset<N> operator@(const bitset<N>& lhs, unsigned long long rhs)
std::bitset
在混合模式功能方面的矛盾特性也存在于 operator==
和 operator!=
中。这些是成员函数,其 rhs 参数具有隐式转换,但 lhs 参数(即 this
指针,受模板参数推导影响)没有。这会导致以下问题:
#include <bitset>
#include <iostream>
int main()
{
constexpr auto N = 64;
constexpr std::bitset<N> b = 0xDEADC0DE; // OK, copy initialization
std::cout << (b == 0xDEADC0DE); // OK, implicit conversion on rhs
std::cout << (0xDEADC0DE == b); // ERROR, no implicit conversion on lhs
}
mybitset |= 0x4;
应该可以编译。 - Andrew Lazarus