问题描述
标准库类模板 std :: bitset< N>
有一个构造函数(C ++ 11及以上, unsigned long
C ++之前的参数11)
The Standard Library class template std::bitset<N>
has a constructor (C++11 and onwards, unsigned long
argument before C++11)
constexpr bitset(unsigned long long) noexcept
与许多最佳实践指南相反,此单参数构造函数未标记为 explicit
。这背后的理由是什么?
Contrary to many best-practice guidelines, this single-argument constructor is not marked as explicit
. What is the rationale behind this?
推荐答案
显式构造
对显式
构造函数的主要反对是无符号整数的复制初始化不再起作用
Explicit construction
The main objection against an explicit
constructor is that copy-initialization from unsigned integers no longer works
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
的泛化,构造函数可能被隐式地促进适应现有的C风格的基于比特 - on raw unsigned int
。使构造函数 explicit
会破坏很多现有代码(现在添加它将同样打破现有代码)。
Since std::bitset<N>
is meant as a generalization of unsigned int
, the constructor was probably made implicit to facilitate adapting existing C-style bit-twiddling code based on raw unsigned int
. Making the constructor explicit
would have broken much existing code (and adding it now will equally break much existing code).
UPDATE :执行一些标准考古学,我发现, bitset
的 unsigned long
构造函数未作显式
(一致投票,但没有动机)。
UPDATE: doing some Standard archeology, I found N0624 from January 1995 that proposed to add the then brand-new keyword explicit
to all single-argument constructors in the pre-Standard Library draft. This was put to a vote at a meeting in March 1995 (Austin). As documented in N0661, the unsigned long
constructor for bitset
was not made explicit
(unanimous vote, but without motivation).
即使 bitset
很容易从 unsigned long
初始化,但是存在其他不完全的混合模式网络操作(&
, |
或 ^
):
However, even though bitset
is easily initialized from unsigned long
, there is otherwise incomplete mixed-mode setwise operations (&
, |
or ^
):
constexpr auto N = 512;
std::bitset<N> b = 0xDEADC0DE; // OK
std::bitset<N> c = b & 0xFFFF; // ERROR, cannot deduce template arguments for rhs
这可以通过提出重载操作符来支持混合-mode bit-twiddling:
This could be remedied by proposing overloaded operators to support mixed-mode bit-twiddling:
// @ 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)
作为成员的重载运算符(< N&函数
关于混合模式功能的 std :: bitset
的精神分裂性质也存在于 operator ==
和 operator!=
。这些是对其rhs参数进行隐式转换的成员函数,但不是它们的lhs参数( this
指针,它受模板参数扣除)。这导致以下结果:
Overloaded operators as member functions
The schizophrenic nature of std::bitset
with respect to mixed-mode functionality is also present in the operator==
and operator!=
. These are member functions that have implicit conversion on their rhs arguments, but not on their lhs argument (the this
pointer, which is subject to template argument deduction). This leads to the following:
#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年提案。主要锁定未来功能的提议的时间 std :: bitset
早于具有非类型模板参数的功能模板。当时唯一可行的解决方法是使所有重载的运算符成员函数,而不是非成员函数。以后,当更高级的模板技术开始使用时,这种情况从未改变过(另见 此问答 为什么这可能破坏代码)。
The origins of this behavior stem from the 1992 proposal N0128. The timing of that proposal, which largely locked in the functionality of the future std::bitset
, was prior to function templates having non-type template parameters. The only feasible workaround at the time was to make all overloaded operators member functions instead of non-member functions. This was never changed later on when more advanced template technology became available (see also this Q&A for why this might break code).
这篇关于为什么带有unsigned long long参数的std :: bitset构造函数没有标记为显式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!