C++
g++
clang++
右辺値参照宣言子
左辺値

「右辺値参照宣言子: &&」の例題をclang++, g++, vc++でコンパイルしてみた


「右辺値参照宣言子: &&」

https://msdn.microsoft.com/ja-jp/library/dd293668.aspx

の例をclang++, g++で編纂(compile)してみた。Visual studioでの実行例は上記で掲載。今回利用した処理系は下記。機材はMacBook Pro, 2.6GHz intel Core i5, 16GB dory.

vc++ はMicrosoft Windows [Version 10.0.17134.165]上のMicrosoft(R) C/C++ Optimizing Compiler Version 19.12.25830.2 for x86

$ clang++ --version

clang version 6.0.0 (tags/RELEASE_600/final)
Target: x86_64-apple-darwin17.7.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin
$ g++-8 --version
g++-8 (Homebrew GCC 8.1.0) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


例題1:string_conctenation.cpp


string_conctenation.cpp

// string_concatenation.cpp  

// compile with: /EHsc
#include <iostream>
#include <string>
using namespace std;

int main()
{
string s = string("h") + "e" + "ll" + "o";
cout << s << endl;
}


clang++, g++, vc++

$ clang++ string_conctenation.cpp -I./ -std=c++14 -Wall

hello
$ clang++ string_conctenation.cpp -I./ -std=c++17 -Wall
hello
$ clang++ string_conctenation.cpp.cpp -I./ -std=c++2a -Wall
hello

$ g++-8 string_conctenation.cpp -I./ -std=c++14 -Wall
hello
$ g++-8 string_conctenation.cpp -I./ -std=c++17 -Wall
hello
$ g++-8 ms.cpp -I./ -std=c++2a -Wall
hello

>cl string_conctenation.cpp /EHsc
Microsoft(R) C/C++ Optimizing Compiler Version 19.12.25830.2 for x86
Copyright (C) Microsoft Corporation. All rights reserved.

string_conctenation.cpp
C:\Program Files (x86)\Microsoft Visual
Microsoft (R) Incremental Linker Version 14.12.25830.2
Copyright (C) Microsoft Corporation. All rights reserved.

/out:string_conctenation.exe
string_conctenation.obj

C:>string_conctenation.exe
hello


例題2:reference-overload.cpp


reference-overload.cpp

// reference-overload.cpp  

// Compile with: /EHsc
#include <iostream>
using namespace std;

// A class that contains a memory resource.
class MemoryBlock
{
// TODO: Add resources for the class here.
};

void f(const MemoryBlock&)
{
cout << "In f(const MemoryBlock&). This version cannot modify the parameter." << endl;
}

void f(MemoryBlock&&)
{
cout << "In f(MemoryBlock&&). This version can modify the parameter." << endl;
}

int main()
{
MemoryBlock block;
f(block);
f(MemoryBlock());
}


clang++, g++, vc++

$ clang++ reference-overload.cpp  -I./ -std=c++14 -Wall

In f(const MemoryBlock&). This version cannot modify the parameter.
In f(MemoryBlock&&). This version can modify the parameter.
$ clang++ reference-overload.cpp -I./ -std=c++17 -Wall
In f(const MemoryBlock&). This version cannot modify the parameter.
In f(MemoryBlock&&). This version can modify the parameter.
$ clang++ reference-overload.cpp -I./ -std=c++2a -Wall
In f(const MemoryBlock&). This version cannot modify the parameter.
In f(MemoryBlock&&). This version can modify the parameter.

$ g++-8 reference-overload.cpp -I./ -std=c++14 -Wall
In f(const MemoryBlock&). This version cannot modify the parameter.
In f(MemoryBlock&&). This version can modify the parameter.
$ g++-8 reference-overload.cpp -I./ -std=c++17 -Wall
In f(const MemoryBlock&). This version cannot modify the parameter.
In f(MemoryBlock&&). This version can modify the parameter.
$ g++-8 reference-overload.cpp -I./ -std=c++2a -Wall
In f(const MemoryBlock&). This version cannot modify the parameter.
In f(MemoryBlock&&). This version can modify the parameter.

>cl reference-overload.cpp /EHsc
Microsoft(R) C/C++ Optimizing Compiler Version 19.12.25830.2 for x86
Copyright (C) Microsoft Corporation. All rights reserved.

reference-overload.cpp
C:\Program Files (x86)\Microsoft Visual
Microsoft (R) Incremental Linker Version 14.12.25830.2
Copyright (C) Microsoft Corporation. All rights reserved.

/out:reference-overload.exe
reference-overload.obj

C:>reference-overload.exe
In f(const MemoryBlock&). This version cannot modify the parameter.
In f(MemoryBlock&&). This version can modify the parameter.


例題3:named-reference.cpp


named-reference.cpp

// named-reference.cpp  

// Compile with: /EHsc
#include <iostream>
using namespace std;

// A class that contains a memory resource.
class MemoryBlock
{
// TODO: Add resources for the class here.
};

void g(const MemoryBlock&)
{
cout << "In g(const MemoryBlock&)." << endl;
}

void g(MemoryBlock&&)
{
cout << "In g(MemoryBlock&&)." << endl;
}

MemoryBlock&& f(MemoryBlock&& block)
{
g(block);
return block;
}

int main()
{
g(f(MemoryBlock()));
}


clang++, g++

$ clang++ named-reference.cpp -I./ -std=c++14 -Wall

named-reference.cpp:25:11: error: rvalue reference to type 'MemoryBlock' cannot bind
to lvalue of type 'MemoryBlock'
return block;
^~~~~
1 error generated.
$ clang++ named-reference.cpp -I./ -std=c++17 -Wall
named-reference.cpp:25:11: error: rvalue reference to type 'MemoryBlock' cannot bind
to lvalue of type 'MemoryBlock'
return block;
^~~~~
1 error generated.
$ clang++ named-reference.cpp -I./ -std=c++2a -Wall
named-reference.cpp:25:11: error: rvalue reference to type 'MemoryBlock' cannot bind
to lvalue of type 'MemoryBlock'
return block;
^~~~~
1 error generated.

$ g++-8 named-reference.cpp -I./ -std=c++14 -Wall
named-reference.cpp: In function 'MemoryBlock&& f(MemoryBlock&&)':
named-reference.cpp:25:11: error: cannot bind rvalue reference of type 'MemoryBlock&&' to lvalue of type 'MemoryBlock'
return block;
^~~~~
$ g++-8 named-reference.cpp -I./ -std=c++17 -Wall
named-reference.cpp: In function 'MemoryBlock&& f(MemoryBlock&&)':
named-reference.cpp:25:11: error: cannot bind rvalue reference of type 'MemoryBlock&&' to lvalue of type 'MemoryBlock'
return block;
^~~~~
$ g++-8 named-reference.cpp -I./ -std=c++2a -Wall
named-reference.cpp: In function 'MemoryBlock&& f(MemoryBlock&&)':
named-reference.cpp:25:11: error: cannot bind rvalue reference of type 'MemoryBlock&&' to lvalue of type 'MemoryBlock'
return block;
^~~~~

e>cl named-reference.cpp /EHsc
Microsoft(R) C/C++ Optimizing Compiler Version 19.12.25830.2 for x86
Copyright (C) Microsoft Corporation. All rights reserved.

named-reference.cpp
C:\Program Files (x86)\Microsoft Visual
named-reference.cpp(25): error C2440: 'return': 'MemoryBlock' から 'MemoryBlock &&' に変換できません。
named-reference.cpp(25): note: 左辺値を右辺値の参照にバインドすることはできません

clang++, g++でエラーになる。

MSのサイトには「左辺値は右辺値参照にキャストできます。」

と書いている。clang++, g++の仕様はこれから確認。

p.s. 20180808追記

VC++でもエラーになった。

@rinse_ さんからのコメントで短い表現の方で試した。


named-reference2.cpp

// named-reference.cpp  

// Compile with: /EHsc
#include <iostream>
using namespace std;

// A class that contains a memory resource.
class MemoryBlock
{
// TODO: Add resources for the class here.
};

void g(const MemoryBlock&)
{
cout << "In g(const MemoryBlock&)." << endl;
}

void g(MemoryBlock&&)
{
cout << "In g(MemoryBlock&&)." << endl;
}

MemoryBlock&& f(MemoryBlock&& block)
{
g(block);
return move(block);// @rinse_ teach me at comment No.1
// original is "return block;"
}

int main()
{
g(f(MemoryBlock()));
}


clang++, g++

$ clang++ named-reference2.cpp -I./ -std=c++14 -Wall

In g(const MemoryBlock&).
In g(MemoryBlock&&).
$ clang++ named-reference2.cpp -I./ -std=c++17 -Wall
In g(const MemoryBlock&).
In g(MemoryBlock&&).
$ clang++ named-reference2.cpp -I./ -std=c++2a -Wall
In g(const MemoryBlock&).
In g(MemoryBlock&&).

$ g++-8 named-reference2.cpp -I./ -std=c++14 -Wall
In g(const MemoryBlock&).
In g(MemoryBlock&&).
$ g++-8 named-reference2.cpp -I./ -std=c++17 -Wall
In g(const MemoryBlock&).
In g(MemoryBlock&&).
$ g++-8 named-reference2.cpp -I./ -std=c++2a -Wall
In g(const MemoryBlock&).
In g(MemoryBlock&&).

>cl named-reference2.cpp /EHsc
Microsoft(R) C/C++ Optimizing Compiler Version 19.12.25830.2 for x86
Copyright (C) Microsoft Corporation. All rights reserved.

named-reference2.cpp
C:\Program Files (x86)\Microsoft Visual
Microsoft (R) Incremental Linker Version 14.12.25830.2
Copyright (C) Microsoft Corporation. All rights reserved.

/out:named-reference2.exe
named-reference2.obj

C:\Users\Administrator\source>named-reference2.exe
In g(const MemoryBlock&).
In g(MemoryBlock&&).


例題4:template-type-deduction.cpp


template-type-deduction.cpp

// template-type-deduction.cpp  

// Compile with: /EHsc
#include <iostream>
#include <string>
using namespace std;

template<typename T> struct S;

// The following structures specialize S by
// lvalue reference (T&), const lvalue reference (const T&),
// rvalue reference (T&&), and const rvalue reference (const T&&).
// Each structure provides a print method that prints the type of
// the structure and its parameter.

template<typename T> struct S<T&> {
static void print(T& t)
{
cout << "print<T&>: " << t << endl;
}
};

template<typename T> struct S<const T&> {
static void print(const T& t)
{
cout << "print<const T&>: " << t << endl;
}
};

template<typename T> struct S<T&&> {
static void print(T&& t)
{
cout << "print<T&&>: " << t << endl;
}
};

template<typename T> struct S<const T&&> {
static void print(const T&& t)
{
cout << "print<const T&&>: " << t << endl;
}
};

// This function forwards its parameter to a specialized
// version of the S type.
template <typename T> void print_type_and_value(T&& t)
{
S<T&&>::print(std::forward<T>(t));
}

// This function returns the constant string "fourth".
const string fourth() { return string("fourth"); }

int main()
{
// The following call resolves to:
// print_type_and_value<string&>(string& && t)
// Which collapses to:
// print_type_and_value<string&>(string& t)
string s1("first");
print_type_and_value(s1);

// The following call resolves to:
// print_type_and_value<const string&>(const string& && t)
// Which collapses to:
// print_type_and_value<const string&>(const string& t)
const string s2("second");
print_type_and_value(s2);

// The following call resolves to:
// print_type_and_value<string&&>(string&& t)
print_type_and_value(string("third"));

// The following call resolves to:
// print_type_and_value<const string&&>(const string&& t)
print_type_and_value(fourth());
}


clang++, g++

$ clang++ template-type-deduction.cpp -I./ -std=c++14 -Wall

print<T&>: first
print<const T&>: second
print<T&&>: third
print<const T&&>: fourth
$ clang++ template-type-deduction.cpp -I./ -std=c++17 -Wall
print<T&>: first
print<const T&>: second
print<T&&>: third
print<const T&&>: fourth
$ clang++ template-type-deduction.cpp -I./ -std=c++2a -Wall
print<T&>: first
print<const T&>: second
print<T&&>: third
print<const T&&>: fourth

$ g++-8 template-type-deduction.cpp -I./ -std=c++14 -Wall
print<T&>: first
print<const T&>: second
print<T&&>: third
print<const T&&>: fourth
$ g++-8 template-type-deduction.cpp -I./ -std=c++17 -Wall
print<T&>: first
print<const T&>: second
print<T&&>: third
print<const T&&>: fourth
$ g++-8 template-type-deduction.cpp -I./ -std=c++2a -Wall
print<T&>: first
print<const T&>: second
print<T&&>: third
print<const T&&>: fourth
>cl template-type-deduction.cpp /EHsc
Microsoft(R) C/C++ Optimizing Compiler Version 19.12.25830.2 for x86
Copyright (C) Microsoft Corporation. All rights reserved.

template-type-deduction.cpp
C:\Program Files (x86)\Microsoft Visual
Microsoft (R) Incremental Linker Version 14.12.25830.2
Copyright (C) Microsoft Corporation. All rights reserved.

/out:template-type-deduction.exe
template-type-deduction.obj

C:\Users\Administrator\source>template-type-deduction.exe
print<T&>: first
print<const T&>: second
print<T&&>: third
print<const T&&>: fourth


課題など

一つコンパイルエラーになった理由を調査中

「error: cannot bind rvalue reference of type to lvalue of type」検索

@rinse_ さんからのコメントで短い表現の方を追記。


参考文献(reference)

一時オブジェクトの寿命と右辺値参照、ムーブセマンティクスのお話

https://qiita.com/rinse_/items/ad0cc7e351e836595c94

Effective Modern C++ Item 24: Distinguish universal references from rvalue references.

https://www.slideshare.net/mooopan/emc24

rvalue reference 完全解説

https://cpplover.blogspot.com/2009/11/rvalue-reference_23.html

C++のつまずきポイント解説 その1

https://qiita.com/_EnumHack/items/a3724dead343b5aecb4e


文書履歴(document history)

ver. 0.10 初稿 20180808 午前

ver. 0.11 @rinse_ さんのコメントに基づき追記。20180808 午後

ver. 0.12 VC++の結果追記 20180808 夕方