标准库类模板 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/