I am using gcc12.2 and find that the following code compiles and produces wierd results try it in godbolt. (PS: Switching to clang shows the same result)
#include <iostream>
void global() { /*std::cout << "global()" << std::endl;*/ }
template <typename T> // universal reference
void invoke(T&& func, const std::string& tag) {
if constexpr (std::is_rvalue_reference_v<T>) {
std::cout << "rvalue reference " << tag << std::endl;
}
else if constexpr (std::is_lvalue_reference_v<T>) {
std::cout << "lvalue reference " << tag << std::endl;
}
else {
std::cout << "non-reference " << tag << std::endl;
}
func();
}
template <typename T>
struct Test {
Test(T&& x, const std::string& tag) // rvalue reference, not universal reference
{
if constexpr (std::is_rvalue_reference_v<T>) {
std::cout << "rvalue reference " << tag << std::endl;
}
else if constexpr (std::is_lvalue_reference_v<T>) {
std::cout << "lvalue reference " << tag << std::endl;
}
else {
std::cout << "non-reference " << tag << std::endl;
}
}
};
int main() {
int && x = 3;
using RRef = void (&&)();
RRef rref = global;
using LRef = void (&)();
LRef lref = global;
std::cout << "RRef is rvalue reference " << std::is_rvalue_reference_v<RRef> << std::endl;
std::cout << "rref is rvalue reference " << std::is_rvalue_reference_v<decltype(rref)> << std::endl;
std::cout << "move(rref) is rvalue reference " << std::is_rvalue_reference_v<decltype(std::move(rref))> << std::endl;
std::cout << "x is rvalue reference " << std::is_rvalue_reference_v<decltype(x)> << std::endl;
std::cout << "move(x) is rvalue reference " << std::is_rvalue_reference_v<decltype(std::move(x))> << std::endl;
std::cout << "==== invoke ==== " << std::endl;
invoke(global, "global");
invoke(rref, "rref");
invoke(std::move(rref), "rref2");
invoke(lref, "lref");
invoke(std::move(lref), "lref2");
std::cout << "==== Test ==== " << std::endl;
Test(global, "global");
Test(rref, "rref");
Test(std::move(rref), "rref2");
Test(lref, "lref");
Test(std::move(lref), "lref2");
std::cout << "==== Test int ==== " << std::endl;
// Test(x, "x"); // cannot bind lvalue to rvalue-reference
Test(std::move(x), "move(x)");
}
The output is as following for gcc 12.2:
RRef is rvalue reference 1
rref is rvalue reference 1
move(rref) is rvalue reference 0 // why is this no longer rvalue reference
x is rvalue reference 1
move(x) is rvalue reference 1
==== invoke ====
lvalue reference global // why are they all lvalue reference
lvalue reference rref
lvalue reference rref2
lvalue reference lref
lvalue reference lref2
==== Test ====
non-reference global // why they are non-reference
non-reference rref
non-reference rref2
non-reference lref
non-reference lref2
==== Test int ====
non-reference move(x)
Could you please explain why we get the following output:
std::move(rref)
is an lvalue reference whilestd::move(x)
is an rvalue reference- when passing the functions to
invoke
, which accepts universal reference, the deduced type are all lvalue-reference, indicating lvalue references are passed to theinvoke
- when passing the functions to
Test
, which accepts only rvalue references, the various inputs are all accepted, indicating they are all rvalue references.
Passing reference of int
behaves normal, while passing reference of function behaves quite wierd.
Aucun commentaire:
Enregistrer un commentaire