2015-11-04 5 views
9

S s = {};と同じになると期待して、コードS s; ... s = {};を書きました。しかし、それはしませんでした。次の例は、問題を再現:オーバーロードの解決:空の中括弧の割り当て

#include <iostream> 

struct S 
{ 
    S(): a(5) { } 
    S(int t): a(t) {} 

    S &operator=(int t) { a = t; return *this; } 
    S &operator=(S const &t) = default; 

    int a; 
}; 

int main() 
{ 
    S s = {}; 

    S t; 
    t = {}; 

    std::cout << s.a << '\n'; 
    std::cout << t.a << '\n'; 
} 

出力は次のようになります。

5 
0 

私の質問は以下のとおりです。

  1. operator=(int)代わりに "曖昧" や他の一つで、ここで選択された理由?
  2. きちんとこの問題を回避するには、Sを変更せずに、ありますか?

私の意図はs = S{};です。それがうまくいくなら、s = {};を書くことは便利だろう。私は現在s = decltype(s){};を使用していますが、タイプまたは変数名を繰り返さないようにしたいと考えています。

+0

'{}'〜 'int'はアイデンティティの変換です([\ [over.ics.list \]/9)(http://eel.is/c++draft/over.ics.list#9 ))。 '{} 'はユーザー定義の変換([\ [over.ics.list \]/6)(http://eel.is/c++draft/over.ics.list#6)です。 )。私は昨日非常に似たような質問をしたことを誓っています... –

+0

@ T.C。もしそうなら、私は昨日より多くの質問を読んで、自分自身でいくつかの開発時間を節約できたと思います! –

+0

私は自分のコードで同じミスを繰り返したようです。私は通常、void clear(){* this = {};を使用します。 } 'オブジェクトをその値で初期化された状態に戻すことを意図している –

答えて

8

operator=(int)ここで選択されたのはなぜ、代わりに「曖昧」または他の1の:ここでは、関連する情報は何ですか? int

{}恒等変換([over.ics.list]/9)です。{}Sは、技術的には{}const S&のユーザー定義の変換で、[over.ics.list]/8と[over.ics.ref]を最初に通過してからover.icsに戻ります。リスト]/6)。

最初の勝ちです。

すっきりした回避策はありますか?

トリックstd::experimental::optionalの変動はt = {}は常にtが空にするために引きます。 鍵はoperator=(int)をテンプレートにすることです。あなたはintだけintを受け入れるようにしたい場合は、それはあなたが(おそらくまた、その場合の基準によって引数を取るようにしたいと思う)の変換を有効にする場合は

template<class Int, std::enable_if_t<std::is_same<Int, int>{}, int> = 0> 
S& operator=(Int t) { a = t; return *this; } 

異なる制約を使用することができなりました。

右のオペランドの型をテンプレートパラメータにすると、{}は推論されないコンテキストなので、t = {}がこのオーバーロードを使用しないようにブロックすることが重要です。

...変更なしS

template<class T> T default_constructed_instance_of(const T&) { return {}; }は、s = default_constructed_instance_of(s);ですか?

+0

最後の行については、テンプレート void reset(T&t){t = T {}; } ' –

-1

まず第一に、ケースが代入演算子の「INT」バージョンとは何の関係もない、あなたはそれを削除することができます。コンパイラによって生成されるので、実際には他の代入演算子も削除することができます。 IEでは、この種の型は自動的にコピー/移動コンストラクタと代入演算子を受け取ります。

S s = {};  // the default constructor is invoked 

ポストである:(つまり、それらは禁止されていないと、あなただけのコンパイラは、明示的な表記法を使用して自動的に何を繰り返している)

最初のケース

コピーの初期化を使用していますコンパイラーはそのような単純なケースを最適化します。あなたが書くべき何秒ケース

はの直接初期化ある

S s;   // the default constructor is invoked if you have it 

:あなたも書くことができます

S s{};  // the default constructor is invoked (as you have it) 

注:あなたは方向の初期化の代わりにを使用する必要がありますコピー割り当ての右側:

t = S{}; 

この表記は、(存在する場合)は、デフォルトのコンストラクタを呼び出す、または(限りタイプが集合体であるように)メンバーの値を初期化します。 http://en.cppreference.com/w/cpp/language/value_initialization

+0

代入演算子の "int"バージョンを削除すると、2番目のケースが(書いたように) – pm100

+1

を取得していない場合、出力は '5 5'です。 –