9

標準ライブラリ クラス テンプレートstd::bitset<N>にはコンストラクターがあります (C++11 以降、unsigned longC++11 より前の引数​​)

constexpr bitset(unsigned long long) noexcept 

多くのベスト プラクティス ガイドラインに反して、この単一引数のコンストラクタは としてマークされていませんexplicit。この背後にある理論的根拠は何ですか?

4

1 に答える 1

5

明示的な構築

コンストラクターに対する主な反論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も参照してください)。

于 2014-09-17T12:44:33.183 に答える