14

は、私は次のインターフェイスを持つC++クラスがあります。C++の一時的な定数はありますか?

class F { 
public: 
    F(int n, int d); 
    // no other constructors/assignment constructors defined 
    F& operator *= (const F&); 
    F& operator *= (int); 
    int n() const; 
    int d() const; 
}; 

をそして、私は次のコードを持っている:

const F a{3, 7}; 
const F b{5, 10}; 
auto result = F{a} *= b; // How does this compile? 

のVisual Studio(VS)2013の下に、コメント行は、エラーなしでコンパイルされます。 VS2015の下で、C2678が生成されたエラー:

error C2678: binary '*=': no operator found 
    which takes a left-hand operand of type 'const F' 
    (or there is no acceptable conversion) 
note: could be 'F &F::operator *=(const F &)' 
note: or  'F &F::operator *=(int)' 
note: while trying to match the argument list '(const F, const F)' 

私の期待はF{a}は、一時的なオブジェクトがresultに割り当てられることになる後、operator *= (b)が適用されるであろうにaの非const一時的なコピーを作成することでした。私は一時的なものが一定であるとは思わなかった。興味深いことに:auto result = F(a) *= b;は、VS2015でエラーなしでコンパイルしますが、私はそれが意味論的に同じであるべきだと考えました。

私の質問は次のとおりです。どの動作が正しいかVS2015またはVS2013 &なぜですか?

F(const F&); 

または変数a非constコードが正常にコンパイルされますあなたはユーザー定義のコピーコンストラクタを指定した場合ので

感謝

+1

一見、バグのように見えますが、 'F {a}'は非constでなければなりません –

+0

他の要因がないことを確認するためにMCVEを投稿できますか? –

+2

明らかに、(const F、const F)初期化子リストを推測しようとしたときに大理石が失われました。代わりに 'F(a)'を使用してください。 connect.microsoft.comを使用してバグを報告してください。 –

答えて

0

私の考えでは、それは、VS2015のバグです。

aからオブジェクトの定数が新しく作成されたオブジェクトに転送されているように見えます。

F{a} 

結果がprvalue(gccとの両方が、この結果を持って打ち鳴らす)でなければなりませんが、それは左辺値を生産している:

+0

コピーctorを明示的にするとどうなりますか?それは私にはキャストとしてそれを使用しているようだ、真正なコピーを必要としないためです。 –

8

のVisual Studio 2015は、のために、正しい結果を生成されていません。 Luc Danton for the VALUE_CATEGORY() code

#include <iostream> 

class F { 
public: 
    F(int n, int d) :n_(n), d_(d) {}; 
    F(const F&) = default ; 
    F& operator *= (const F&){return *this; } 
    F& operator *= (int) { return *this; } 
    int n() const { return n_ ; } 
    int d() const { return d_ ; } 
    int n_, d_ ; 
}; 

template<typename T> 
struct value_category { 
    static constexpr auto value = "prvalue"; 
}; 

template<typename T> 
struct value_category<T&> { 
    static constexpr auto value = "lvalue"; 
}; 

template<typename T> 
struct value_category<T&&> { 
    static constexpr auto value = "xvalue"; 
}; 

#define VALUE_CATEGORY(expr) value_category<decltype((expr))>::value 

int main() 
{ 
    const F a{3, 7}; 
    const F b{5, 10}; 
    std::cout << "\n" << VALUE_CATEGORY(F{a}) << "\n"; 
} 

Hatのヒント:私はこの結果を生成するためにOPの次のコードの修正版を使用しています。 Visual Studioは比較的最近のバージョンを持っているwebcompilerを使用して

は生成します。

lvalue 

私たちが見ているエラーを生成するために、この場合ののconstでなければなりません。 gccと打ち鳴らすの両方ながら(see it live)プロデュース:

prvalue 

これは均等に不可解なVisual Studioのバグstd::move of string literal - which compiler is correct?に関連することができます。我々はのconst Fを使用してgccと打ち鳴らすと同じ問題を得ることができます

注:

using cF = const F ; 
auto result = cF{a} *= b; 

ので、Visual Studioが私たちに間違った値カテゴリを与えているだけでなく、それはまた、任意CV-修飾子を追加します。

Hansは、F(a)を使用してあなたの質問に彼のコメントで述べたように、正しく値を生成するので、期待される結果が得られます。

ドラフトC++標準の関連セクションは言う部5.2.3[expr.type.conv]ある:

を同様に、単純型指定子または型名指定子はbraced-続いinit-listは、指定されたbraced-init-listで指定されたタイプdirect-list-initialized(8.5.4)の一時的な オブジェクトを作成し、その値は です。

注意してください限り、これは"old MSVC lvalue cast bug"ではありません。この問題の解決策は、この問題を修正しない/Zc:rvalueCastを使用することです。この問題は、私が知っている限り、以前の問題で起こっていないcv修飾子の誤った追加でも異なります。

+0

ああ、それは古いMSVC lvalueキャストバグです。彼らは初期化をリストアップするためにそれを永続化していないかもしれないと考えた... –

+0

@ M.Mあなたはどのように知っていますか?限り、私は解決策(ここに記載)(http://stackoverflow.com/a/26508755/1708801)は、この問題を修正しない '/ Zc:rvalueCast'を使うことです。 –

+0

私はあなたの答え(?) –

0

Visual C++には、IDキャストが一時的なものではなく、元の変数を参照するバグがありました。

ここにバグレポート:http://en.cppreference.com/w/cpp/language/copy_elisionからidentity cast to non-reference type violates standard

+0

私はそれが[この質問](http://stackoverflow.com/a/26508755/1708801)と同じ問題であることを理解する限り、それは同じバグだとは思わないし、解決策は使用することです'/ Zc:rvalueCast'ここで問題を解決しません。 –

0

:次の状況下では

は、コンパイラは 著作を省略しても、コピー/移動コンストラクタた場合にクラスオブジェクトの-コンストラクタを移動することが許可されています とデストラクタには、観察可能な副作用があります。 無名一時は、任意の参照に結合していない、移動される又は トップレベルのCV-を無視して同じタイプ(のオブジェクトにコピー

.......

資格)、コピー/移動は省略されています。その一時的なものが であるときには、それは に移動またはコピーされるストレージに直接構築されます。名前のない一時的な文字列がreturn文の 引数である場合、このコピー・エリジョンの変形は RVO "戻り値の最適化"と呼ばれます。

したがって、コンパイラにはコピーを無視するオプションがあります(この場合、非const型への暗黙的なキャストとして機能します)。

関連する問題