显式构造
反对的主要反对意见是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
Since std::bitset<N>
是为了概括unsigned int
,构造函数可能是隐式的,以便于适应基于原始的现有 C 风格的位操作代码unsigned int
。制作构造函数explicit
会破坏许多现有代码(现在添加它同样会破坏许多现有代码)。
UPDATE:做了一些标准考古学,我发现N0624 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1995/N0624.asc从1995年1月开始建议添加当时全新的关键字explicit
预标准库草案中的所有单参数构造函数。 1995 年 3 月(奥斯汀)的一次会议上对此进行了表决。如记录在N0661 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1995/N0661.pdf, the unsigned long
构造函数bitset
没有被制作explicit
(一致投票,但没有动机)。
混合模式位调整
然而,尽管bitset
很容易初始化unsigned long
,否则存在不完整的混合模式集合操作(&
, |
or ^
):
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==
and 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
}
这种行为的起源源于 1992 年的提案N0128 http://www.open-std.org/Jtc1/sc22/wg21/docs/papers/1992/WG21%201992/X3J16_92-0051%20WG21_N0128.pdf。该提案的时机,很大程度上锁定了未来的功能std::bitset
,早于具有非类型模板参数的函数模板。当时唯一可行的解决方法是使所有重载运算符成为成员函数而不是非成员函数。后来当更先进的模板技术可用时,这一点从未改变(另请参阅本次问答 https://stackoverflow.com/q/26089156/819272为什么这可能会破坏代码)。