web-dev-qa-db-ja.com

コンストラクターとキャスト演算子

私はライブラリをプログラミングしています(そのため、上記のすべてのクラスに完全にアクセスできます)。 2つのクラス(AB)は基本的に同じであり、実装のみが異なるため、簡単に相互に変換できます。ただし、B型の引数をAのコンストラクタの1つに渡すか、BAに暗黙的にキャストして変換する場合、好ましい。説明する2つのコード例:

キャストの使用:

class A
{
public:
    int c[3];
    operator B() const
    {
        //return B(...);
    }
};

class B
{
public:
    int a, b, c;
    operator A() const
    {
        //return A(...);
    }
};

コンストラクターの使用:

class A
{
public:
    A(const B& b)
    {
        //...
    }
    int c[3];
};

class B
{
public:
    B(const A& a)
    {
        //...
    }
    int a, b, c;
};

両方のアプローチの長所と短所は何ですか?どちらを使用するべきですか?そして、誰かがライブラリを拡張し、いくつかのコンストラクタでexplicitキーワードを使用した場合、いくつかの問題が発生する可能性がありますか?

4
user108376

このような変換を実行する一般的な方法は、コンストラクターを使用することです。型キャスト演算子は、プリミティブ型(ほとんどの場合boolまたは効果的にブール値のように機能するもの)への変換、または追加のコンストラクターを追加できない型にのみ効果的に使用されます。

型キャスト演算子は、コンストラクタを変換するよりも予期しないときに呼び出されるリスクがはるかに大きいため、通常は細心の注意を払って処理する必要があります。

標準ライブラリで型変換演算子を使用する有益な例の1つは、std::stringからstd::string_viewへの変換です。単純なコードを考えてみましょう:

std::string s("string");
std::string_view sv(s);

std::string_viewのコンストラクタはstd::stringを受け入れず、変換は演算子で実行されます

operator std::string_view<...>() const noexcept;

std::stringクラス内。

このデザインの動機は、以下に引用するMarshall Clowの this document (P0254R2)にあります。

string_viewが提案されたとき... stringstring_viewの間の接続はすべてstring_viewで行われていました。 string_viewには以下が含まれます:

  • stringからの暗黙の変換
  • メンバー関数to_string。新しい文字列を作成します。

これは逆だと思います。 string_viewstringについて何も認識していない必要があり、stringは型間の変換を処理する必要があります。具体的には、stringには以下が必要です。

  • string_viewへの暗黙の変換
  • string_viewからの明示的なコンストラクター。

根拠

  • string_viewを基本的な語彙タイプとして使用すると、効率が向上します。

... stringからstring_viewを作成するのは簡単です。したがって、暗黙的に変換されます。 string_viewからstringを作成するのは安価ではないため、明示的に行う必要があります。

  • 他の文字列タイプのサポート。

...独自の文字列クラスからデータを出力することを検討してください... home_stringoperator<<の実装はかなりの作業量であり、iostreamsインフラストラクチャ全体の合理的に完全な知識が必要です。一方、string_viewを使用すると、誰かが次のように書くことができます。

template<...>
ostream<...>& operator<<(ostream<...>& os, const home_string<...>& str)
{
    return os << string_view<...>(str);
}

すべてのフォーマットなどを「無料」で入手できます。

3
Evg