標準ライブラリ クラス テンプレートstd::bitset<N>
にはコンストラクターがあります (C++11 以降、unsigned long
C++11 より前の引数)
constexpr bitset(unsigned long long) noexcept
多くのベスト プラクティス ガイドラインに反して、この単一引数のコンストラクタは としてマークされていませんexplicit
。この背後にある理論的根拠は何ですか?
標準ライブラリ クラス テンプレートstd::bitset<N>
にはコンストラクターがあります (C++11 以降、unsigned long
C++11 より前の引数)
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
、生の に基づく既存の C スタイルのビット操作コードの適応を容易にするために、コンストラクターはおそらく暗黙的に作成されましたunsigned int
。コンストラクターを作成するexplicit
と、既存のコードの多くが壊れてしまいます (そして、コンストラクターを追加すると、既存のコードの多くが同様に壊れます)。
更新: いくつかの標準考古学を行っているときに、 1995 年 1 月のN0624explicit
を見つけました。これは、標準ライブラリ以前のドラフトのすべての単一引数コンストラクターに当時の新しいキーワードを追加することを提案していました。これは、1995 年 3 月 (オースティン) の会議で投票にかけられました。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
混合モード機能に関するの統合失調症の性質は、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
非型テンプレート パラメータを持つ関数テンプレートの前でした。当時の唯一の実行可能な回避策は、オーバーロードされたすべての演算子を非メンバー関数ではなくメンバー関数にすることでした。これは、より高度なテンプレート テクノロジが利用可能になった後も変更されませんでした (これによりコードが壊れる理由については、この Q&Aも参照してください)。