标准库类模板std::bitset<N>有一个构造函数(C++11及以后,C++11之前的unsigned long参数)
constexpr bitset(unsigned long long) noexcept 与许多最佳实践指南相反,这个单参数构造函数没有标记为explicit。这背后的理据是甚麽?
发布于 2014-09-17 12:44:33
显式结构
对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会破坏许多现有代码(现在添加它将同样地破坏许多现有代码)。
UPDATE:做一些标准考古学,我从1995年1月发现了N0624,它提议在标准库草案前的所有单参数构造函数中添加新的关键字explicit。1995年3月在奥斯汀举行的一次会议上对此进行了表决。正如N0661中所记录的,bitset的unsigned long构造函数不是explicit (一致投票,而是没有动机)。
混合模式位旋转
然而,尽管bitset很容易从unsigned long初始化,但在其他情况下存在不完全的混合模式setwise操作(&、|或^):
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提案。该提案的时间主要锁定在未来std::bitset的功能中,其时间优先于具有非类型模板参数的函数模板。当时唯一可行的解决办法是使所有重载的运算符成员函数而不是非成员函数。后来,当更高级的模板技术可用时,这一点从未改变过(请参见this Q&A了解为什么会破坏代码)。
https://stackoverflow.com/questions/25833391
复制相似问题