问题
The question related to this one. By tracing slt_pair. h
and move. h
, it's seems that the difference between Clang and G++ is internally. I have tried to simulate the assignment of the object (pair.first) as same as the implementation of std_pair.h
, the output is same as Clang output it's reasonable output, but why when using pairs it's changes.
#include <iostream>
struct Foo {
Foo() {
std::cout << "default" << std::endl;
}
Foo(Foo& f2) {
std::cout << "non-const" << std::endl;
}
Foo(const Foo& f2) {
std::cout << "const" << std::endl;
}
};
// static_cast Foo lvalue to rvalue
Foo cast1(Foo foo){
return static_cast<Foo&&>(foo);
}
// same : check weather foo and Foo are the same type
Foo cast2(Foo foo){
return static_cast<typename std::remove_reference<Foo>::type&&>(foo);
}
int main() {
Foo T1; // pair Foo object
std::cout<<"Start"<<std::endl;
std::cout<<std::endl;
// (&&) rvalue casting
T1 = cast2(Foo()); // First pair object
std::cout << std::endl;
Foo const foo = T1;// Second pair object
}
How Clang deals with conversion lvalue
to rvalue
and what the real reason for these different outputs.
Any opinion is highly appreciated, Thanks.
Update: I have got a satisfying answers on the comments section of the accepted one.
回答1:
I think not everything in your example does what you think it does. The static_cast
in the returns is meaningless, the result of cast1
and cast2
will automatically be an rvalue since you return by value. Further, cast1
and cast2
are also internally identical since std::remove_reference_t<Foo>
is just Foo
. You would need remove_reference
if you had some templating going on.
Furthermore, you are mixing assignments with constructions. In T1 = cast2(Foo());
the following happens:
- A unnamed temporary is constructed by
Foo()
. This outputsdefault
- This temporary is copied to the
foo
argument ofcast2
. This outputsconst
, since we try to construct aFoo
object from a temporary, and onlyconst Foo&
, notFoo&
, can bind to a temporary. - The
static_cast
does pretty much nothing. foo
is returned. By return value optimization, the constructor that should be called, is not called.- We assign the returned value by using the default (and implicit) assignment operator
T1.operator=(const Foo&)
. Nothing gets printed.
In Foo const foo = T1
you call a constructor. Since T1
is an lvalue, you will call the constructor Foo(Foo&)
and non-const
is printed.
来源:https://stackoverflow.com/questions/62128493/clang-vs-g-lvalue-to-rvalue-conversion