2

文字列のベクトルを返す関数があります

std::vector<std::string> getNames()
{
std::vector<std::string> names;
names.push_back("one");
return names;
}

次のシグネチャを持つコンストラクターを持つ別のクラスがあります (これは実際には TCLAP からのものです)。

ValuesConstraint(std::vector<T>& allowed);

次のことをしようとすると、エラーが発生します

ValuesConstraint<std::string> A( getNames() );

しかし、私が次のことをするときではありません

std::vector<std::string> v = getNames();
ValuesConstraint<std::string> A( v );

これは GCC 4.4.7 で発生しますが、VS2010 では発生しません。エラーは次のとおりです。

error: no matching function for call to ‘TCLAP::ValuesConstraint<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::ValuesConstraint(std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >)’

note: candidates are: TCLAP::ValuesConstraint<T>::ValuesConstraint(std::vector<T, std::allocator<_CharT> >&) [with T = std::basic_string<char, std::char_traits<char>, std::allocator<char> >]

note:                 TCLAP::ValuesConstraint<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >::ValuesConstraint(const TCLAP::ValuesConstraint<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >&)

このエラーが発生する理由と、戻り値をコンストラクターに直接渡すにはどうすればよいですか?

4

1 に答える 1

4

このエラーが発生する理由と、戻り値をコンストラクターに直接渡すにはどうすればよいですか?

のコンストラクターはValuesConstraint<>左辺値 (非への左辺値参照は左辺値にconstのみバインドできます) を受け入れますが、参照型を返さない関数呼び出し式はrvaluesです。

左辺値参照は右辺値にバインドできないため、テンポラリをのコンストラクタに渡すことはできませんValuesConstraint<>(テンポラリは右辺値です)。

左辺値右辺値という用語がわかりにくい場合は、(直感的に) 左辺値を次のように考えることができます。

  • 名前付き変数 (実際には識別子); および/または
  • アドレスを取得できるオブジェクト (実際には式)

それらは通常、プログラムで繰り返し参照できるオブジェクトを示し、安定したアイデンティティーを持ち、そこから暗黙的に移動することは安全ではありません(後でプログラムで参照される可能性があるため)。

逆に、右辺値は次のように表示できます。

  • 一時オブジェクトなどの名前のないオブジェクト。および/または
  • リテラル ( 42false、 など3.14); および/または
  • std::move()から移動しようとしている「不安定な」アイデンティティ ( の結果など) を持つオブジェクトを表す式

これらは通常、プログラム内で繰り返し参照できないオブジェクト (または明示的に を呼び出して再割り当てする前に参照しないことをstd::move()約束したオブジェクト) を表し、したがって移動しても安全です。

ただし、上記を一粒の塩で解釈してください。これは、値カテゴリとは何か、特定の式の値カテゴリが何であるかを判断する方法について直感を構築するために使用できるガイドラインにすぎません。形式的に言えば、物事はもう少し複雑で、上記の一般化が常に正しいとは限りません。

この状況では、例に戻ります。

std::vector<std::string> v = getNames();
//                       ^
//                       Named variable! Can take its address! lvalue!
ValuesConstraint<std::string> A( v );
//                               ^
//                               OK! The constructor accepts an lvalue
//                               reference to non-const, and I am giving
//                               it an lvalue

コンストラクターに左辺値を渡していますが、すべて正常に動作します。一方、この状況では、次のようになります。

ValuesConstraint<std::string> A( getNames() );
//                               ^^^^^^^^^^
//                               getNames() returns a vector by value, this
//                               means a temporary will be constructed as the
//                               return value of the function, and temporaries
//                               are unnamed... so, that's an rvalue!
//                               And the constructor accepts an lvalue reference
//                               to non-const! So this is an ERROR!

非への左辺値参照を受け入れる関数に右辺値を渡そうとしていますconst(つまり、変更可能な左辺値が必要です)。それは違法であり、コンパイラはそれについて不平を言います。

これは GCC 4.4.7 で発生しますが、VS2010 では発生しません

これは、VC10 が非準拠のコンパイラ拡張機能を実装しているためです。これにより、右辺値を左辺値参照にバインドして非const. ただし、これは標準的な動作ではないことに注意してください。移植性のあるコードを書きたい場合は、これに依存しないでください (とにかく、実際には依存しないことをお勧めします)。

コメントで Jesse Good が示唆しているように、警告レベルを 4 に上げて、コンパイラから警告を受け取り、この非標準の拡張機能を使用している状況を検出します。

于 2013-07-08T20:49:02.963 に答える