c++ - 为什么带有 unsigned long long 参数的 std::bitset 构造函数未标记为显式?

标签 c++ implicit-conversion bitset unsigned-long-long-int explicit-constructor

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

constexpr bitset(unsigned long long) noexcept 

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

最佳答案

显式构造

主要反对 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会破坏很多现有代码(现在添加它同样会破坏很多现有代码)。

更新:做一些标准考古,我发现了N0624从1995年1月提出增加当时全新的关键词explicit标准库前草案中的所有单参数构造函数。这在 1995 年 3 月的一次 session 上付诸表决(奥斯汀)。如 N0661 中所述, unsigned long bitset 的构造函数没有制作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 的精神 split 性质关于混合模式功能也存在于 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
}

这种行为的起源源于 1992 年的提案 N0128 .该提议的时机,很大程度上锁定了 future 的功能std::bitset , 在具有非类型模板参数的函数模板之前。当时唯一可行的解​​决方法是让所有重载的运算符成为成员函数而不是非成员函数。这在后来更高级的模板技术可用时从未改变(另请参阅 this Q&A 为什么这可能会破坏代码)。

关于c++ - 为什么带有 unsigned long long 参数的 std::bitset 构造函数未标记为显式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25833391/

相关文章:

c++ - 当条件为真时,有什么方法可以连接宏参数吗?

c++ - 各种常量/静态变量的链接

c++ - 从 boost::bind_t 自动转换为 boost::function

c++ - 编译器在传递 const 变量 : template argument is not a constant expression 时返回错误

c++ - bitset 操作的推荐做法是什么?

c++ - 是否有任何免费工具可以帮助自动生成代码?

C++ __glibcxx* 函数调用的目的是什么?

c - C99 中复杂算术的类型安全

c++ - 0 值的自动整数转换失败

c++ - 挤奶牛,解决方案说明