C++03 では、テンポラリは暗黙的に変更できないと聞いています。
ただし、GCC 4.3.4 (C++03 モード) では次のようにコンパイルされます。
cout << static_cast<stringstream&>(stringstream() << 3).str();
これはどのようにコンパイルされていますか?
(参照への一時的なバインドに関する規則については話していません。)
C++03 では、テンポラリは暗黙的に変更できないと聞いています。
それは正しくありません。一時変数は、特に右辺値を評価することによって作成され、非 const 右辺値と const 右辺値の両方があります。式の値カテゴリとそれが表すオブジェクトの constness は、ほぼ直交しています1。観察:
std::string foo();
const std::string bar();
上記の関数宣言を考えると、式foo()
は非 const 一時変数を作成する非bar()
const 右辺値であり、const 一時変数を作成する const 右辺値です。
オブジェクトを変更できるように、非 const 右辺値で任意のメンバー関数を呼び出すことができることに注意してください。
foo().append(" was created by foo") // okay, modifying a non-const temporary
bar().append(" was created by bar") // error, modifying a const temporary
はメンバー関数であるためoperator=
、非 const 右辺値に代入することもできます。
std::string("hello") = "world";
これは、一時変数が暗黙的に constではないことを納得させるのに十分な証拠です。
1: 42 などのスカラー右辺値は例外です。これらは常に非 constです。
まず、「一時的なものを変更する」と「右辺値を使用してオブジェクトを変更する」には違いがあります。前者は議論するのにあまり役に立たないので、後者を検討します[1]。
3.10/10
私は(3.10/5
C ++ 11で)次のものを見つけました:
オブジェクトを変更するには、オブジェクトの左辺値が必要です。ただし、特定の状況下でクラスタイプの右辺値を使用して、その指示対象を変更することもできます。[例:オブジェクト(9.3)に対して呼び出されたメンバー関数は、オブジェクトを変更できます。]
したがって、右辺値const
自体は変更できませんが、特定の状況を除いてすべて変更できません。
ただし、メンバー関数呼び出しが右辺値を変更できることは、右辺値を介してオブジェクトを変更するケースの大部分が満たされていることを示しているように思われます。
(obj1+obj2).show()
特に、非const
show()
[うーん、なぜ?!]には無効なアサーション(私がリンクした元の質問で)は誤りでした。
したがって、答えは(結論のために質問の文言を少し変更する)、メンバー関数を介してアクセスされる右辺値は本質的に変更不可能ではないということです。
[1]-特に、元の右辺値から一時値への左辺値を取得できる場合は、それを使用して好きなことを行うことができます。
#include <cstring>
struct standard_layout {
standard_layout();
int i;
};
standard_layout* global;
standard_layout::standard_layout()
{
global = this;
}
void modifying_an_object_through_lvalue(standard_layout&&)
{
// Modifying through an *lvalue* here!
std::memset(global, 0, sizeof(standard_layout));
}
int main()
{
// we pass a temporary, but we only modify it through
// an lvalue, which is fine
modifying_an_object_through_lvalue(standard_layout{});
}
(コードを提供してくれたLuc Dantonに感謝します!)