Visual Studio 2022(VC17)においてC++言語標準を「Preview - Features from the Latest C++ Working Draft (/std:c++latest)」に設定してVisual Studio 2017(VC15、C++14)のソースをコンパイルしたところ、参照型引数に「右辺値」を渡すことが禁止されていた。
この「右辺値」は、古いC++ではあまり気にすることのなかった概念であるが、cpprefjpによれば、「名前を持たない一時的なオブジェクト」だとざっくり説明されており、関数の戻り値なども含まれる。
以下はエラーになる場合とならない場合の例。
#include <iostream> #include <vector> using namespace std; struct attr { int val; attr() : val(rand()){} }; void accept_copy(attr _v) { cout << _v.val << endl; } void accept_rval(attr &&_v) { cout << _v.val << endl; } void donot_accept_rval(attr &_v) { cout << _v.val << endl; } attr gen() { vector<attr> v(5); return v[rand() % 5]; } int main() { accept_copy(attr()); accept_rval(attr()); donot_accept_rval(attr());// error accept_rval(gen()); donot_accept_rval(gen());// error }
引数に右辺値を渡してはいけない場合を明示的に指定できるように成ったところは型に厳しい言語としては今までなかったことが不思議といったところだろうか。
しかし実は、C++11などの古い標準の仕様でプログラミングする時でも、Effective C++などの書籍などでは、特にコンストラクタによって生成された右辺値を関数の引数として直接渡す事は良くないとされてきた。
参照でもポインタでもないただのコピーとして右辺値を引き受けることは禁止されていないようだが、これもまた、効率が悪いので、どうしてもコピーでなければ行けない様な場合を除いてコーディング規約では禁止とされる場合が多いだろう。