9

标准库类模板std::bitset<N>有一个构造函数(C++11 及更高版本,unsigned longC++11 之前的参数)

constexpr bitset(unsigned long long) noexcept 

与许多最佳实践指南相反,此单参数构造函数未标记为explicit. 这背后的原因是什么?

4

1 回答 1

5

显式构造

反对构造函数的主要反对意见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 intunsigned int. 制作构造函数explicit会破坏很多现有代码(现在添加它同样会破坏很多现有代码)。

更新:做一些标准考古,我发现1995 年 1 月的N0624explicit建议在标准库草案之前的所有单参数构造函数中添加 then 全新的关键字。1995 年 3 月(奥斯汀)的一次会议上对此进行了表决。正如N0661中所记录的,unsigned long构造函数 forbitset没有做出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==andoperator!=中。这些成员函数在它们的 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提案。该提案的时间安排在很大程度上锁定了未来的功能std::bitset,是在具有非类型模板参数的功能模板之前。当时唯一可行的解​​决方法是让所有重载的运算符成为成员函数,而不是非成员函数。当更高级的模板技术可用时,这从未改变过(另请参阅此问答了解为什么这可能会破坏代码)。

于 2014-09-17T12:44:33.183 回答