4

このコード

struct T {
    int m_x;
    T(int x) : m_x(x) {}

    operator T() {
        return T(0);
    }
};

int main() {
    volatile T v(2);

    T nv(1);
    nv = v; // nv.m_x = 0
}

与えます:

prog.cpp: In function ‘int main()’:
prog.cpp:14:10: error: no match for ‘operator=’ in ‘nv = v’
prog.cpp:14:10: note: candidates are:
prog.cpp:1:8: note: T& T::operator=(const T&)
prog.cpp:1:8: note:   no known conversion for argument 1 from ‘volatile T’ to ‘const T&’
prog.cpp:1:8: note: T& T::operator=(T&&)
prog.cpp:1:8: note:   no known conversion for argument 1 from ‘volatile T’ to ‘T&&’

これを機能させるには、どの型キャスト オーバーロードを定義する必要がありますか?

4

3 に答える 3

5

簡単な答え:

はい、できますが、コンパイラはあなたのために仕事をしません。

volatile T から T へのコンパイラ提供の変換は使用できませんが、volatile 修飾されたコンストラクターを使用したユーザー定義の暗黙的な変換は使用できません。


また、特別なメンバー関数の明示的にデフォルト設定されたバージョンを使用して、そのような変換を宣言することもできません (参考のために長い回答を参照してください)。

このような割り当てを有効にするには、ユーザー定義の変換方法を提供する必要があります。次のいずれかを実行できます

  • 暗黙的なユーザー定義の変換のために cv 修飾された引数を持つ非明示的なコピー コンストラクターを使用するか、
  • v 修飾された引数を取るコピー代入演算子。

例:

X (X const volatile & xo);
X& operator= (X const volatile & xo);


標準的な引用符 'n stuff または

なぜコンパイラは私のためにこれをしないのですか?

方法 1: volatile T からのユーザー提供のコンストラクター

標準、ISO 14882:2011、4/3

ある発明された一時変数 t (8.5) に対して、宣言が整形式でeある場合にのみ、式を暗黙的に型 T に変換できます。T t=e;

宣言T t = e;(この場合eは typed volatile T) は、そのようなコピー初期化が有効である必要があるため、揮発性 T からのコピー コンストラクターが必要になります。

私はすでに答えました (揮発性からのデフォルトのコピーコンストラクターが提供されないのはなぜですか? )。したがって、揮発性 T から T をコピー初期化するユーザー定義の方法を提供する必要があります。

X (X const volatile & xo);

ノート:

  • これは宣言であり、定義も提供する必要があります。
  • コンストラクターは明示的であってはなりません。
  • volatile 引数を取るユーザー定義のコピー コンストラクターを提供すると、暗黙的に生成された既定の代入演算子がなくなります。

これにより、割り当てが機能します。

方法 2: volatile T からのユーザー指定のコピー代入演算子

サンプル コードの割り当てを機能させるもう 1 つの方法は、コピー割り当て演算子です。

残念ながら、この標準では、揮発性オブジェクトを非揮発性オブジェクトに変換するための暗黙的なコピー代入演算子をコンパイラが提供しないとも述べています。

標準、ISO 14882:2011、12.8/18

クラス定義でコピー代入演算子が明示的に宣言されていない場合は、暗黙的に宣言されます。クラス定義でムーブ コンストラクターまたはムーブ代入演算子が宣言されている場合、暗黙的に宣言されたコピー代入演算子は削除済みとして定義されます。それ以外の場合は、デフォルト (8.4) として定義されます。クラスにユーザー宣言のコピー コンストラクターまたはユーザー宣言のデストラクタがある場合、後者のケースは推奨されません。クラス X の暗黙的に宣言されたコピー代入演算子は、次の形式になります。

X& X::operator=(const X&)

もしも

  • X の各直接基底クラス B には、パラメーターが const B&、const volatile B& または B 型のコピー代入演算子があり、
  • クラス型 M (またはその配列) である X のすべての非静的データ メンバーに対して、そのような各クラス型は、パラメーターが型 const M&、const volatile M& または M であるコピー代入演算子を持ちます。122

それ以外の場合、暗黙的に宣言されたコピー代入演算子は次の形式になります。

X& X::operator=(X&)

12.8/18 の 122 に注意してください

暗黙的に宣言されたコピー代入演算子の参照パラメーターは、揮発性の左辺値にバインドできません。C.1.9を参照してください。

他の回答では、C.1.9 を引用しました。

暗黙的に宣言されたコピー コンストラクターと暗黙的に宣言されたコピー代入演算子は、揮発性左辺値のコピーを作成できません。[ ... ]

その結果、必要に応じて適切なコピー代入演算子を提供する必要があります。

X& operator= (X const volatile & xo);

また、明示的にデフォルト設定された volatile から割り当て/コンストラクターを宣言できないことにも注意してください。

C++11 標準 8.4.2/1

明示的にデフォルト設定された関数は、

  • 特別なメンバー関数になり、
  • 同じ宣言された関数型を持っている (ref 修飾子が異なる可能性があることと、コピー コンストラクターまたはコピー代入演算子の場合を除き、パラメーターの型は "非 const T への参照" である場合があります。ここで、T は関数の名前です)。暗黙的に宣言されたかのようにメンバー関数のクラス)、および
  • デフォルトの引数はありません。

次の注記は最終的な C++11 標準から削除されましたが、ドラフト N3242 には含まれていました。それはまだ保持されます。

[ 注:これは、パラメーターの型、戻り値の型、およびcv 修飾子が、仮想の暗黙の宣言と一致する必要があることを意味します。—終わりのメモ]

仮想の暗黙の宣言は非揮発性であるため、デフォルトにすることはできません。

于 2013-06-20T17:59:16.927 に答える
1

揮発性ソースを許可するコピー コンストラクターとコピー割り当てを取得する方法は次のとおりです。

struct X {
  X(const X& o) : members(o.members) {}
  X(const volatile X& o) : members(o.members) {}
  X& operator=(const X& o) {v=o.v; return *this;}
  X& operator=(const volatile X& o) {v=o.v; return *this;}
};

ただし、これにはいくつかの影響があることに注意してください。この型はもはや POD ではなく、簡単にコピーすることさえできません。これは、揮発性にするという全体のポイントを無効にする可能性があります。

于 2013-06-20T18:04:00.740 に答える
0

代入演算子を実装できます=:

T& operator=(const volatile T &rhs) {
    m_x = rhs.m_x;
    return *this;
}
于 2013-06-20T18:04:09.203 に答える