为什么使用unsigned long long参数的std::bitset构造函数没有标记为explicit?

10

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

constexpr bitset(unsigned long long) noexcept 

与许多最佳实践指南相反,这个单参数构造函数没有标记为explicit。这背后的理由是什么?

1
C++标准库有相当多值得质疑的设计决策。 - n. m.
@n.m. 当然,我正在寻找一个答案来确定是否应该提交一个缺陷报告;-) - TemplateRex
作为一种猜测,因为操作符未被重载以接受无符号整数,所以这种方式的代码,如mybitset |= 0x4;应该可以编译。 - Andrew Lazarus
“std::bitset<32> bs = 0x0FFFFFFF;” 这段代码或许有意义,可以编译通过。但无论如何,我怀疑他们会在这个时候明确它——因为这会导致太多的代码出现问题。 - T.C.
1个回答

5

显式构造函数

对于一个显式构造函数的主要反对意见是,从无符号整数进行复制初始化将不再起作用。

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所记录的那样,bitsetunsigned 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
}

这种行为的起源可以追溯到1992年的N0128提案。当时,函数模板还没有非类型模板参数的功能,因此唯一可行的解决方法是将所有重载运算符的函数定义为成员函数而不是非成员函数。后来虽然出现了更先进的模板技术,但这种做法从未改变(也可参见this Q&A,了解为什么这可能会破坏代码)。

3
b & 0xFFFF 无论如何都不起作用 - T.C.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接