| // PR c++/101165 - P2266R1 - Simpler implicit move |
| // { dg-do compile { target c++23 } } |
| // Tests from P2266R1. |
| |
| namespace std { |
| template<typename _Tp> |
| struct remove_reference |
| { typedef _Tp type; }; |
| |
| template<typename _Tp> |
| struct remove_reference<_Tp&> |
| { typedef _Tp type; }; |
| |
| template<typename _Tp> |
| struct remove_reference<_Tp&&> |
| { typedef _Tp type; }; |
| |
| template<typename _Tp> |
| constexpr typename std::remove_reference<_Tp>::type&& |
| move(_Tp&& __t) noexcept |
| { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } |
| } |
| |
| template<typename T, typename U> |
| struct same_type { static const bool value = false; }; |
| |
| template<typename T> |
| struct same_type<T, T> { static const bool value = true; }; |
| |
| struct Widget { |
| Widget(Widget&&); |
| }; |
| |
| struct RRefTaker { |
| RRefTaker(Widget&&); |
| }; |
| |
| struct Mutt { |
| operator int*() &&; |
| }; |
| |
| struct Jeff { |
| operator int&() &&; |
| }; |
| |
| struct Ella { |
| operator int() &&; |
| }; |
| |
| Widget one(Widget w) { |
| return w; // OK since C++11 |
| } |
| |
| RRefTaker two(Widget w) { |
| return w; // OK since C++11 + CWG1579 |
| } |
| |
| RRefTaker three(Widget&& w) { |
| return w; // OK since C++20 because P0527 |
| } |
| |
| // Tests that implicit move applies even to functions that return references. |
| Widget&& four(Widget&& w) { |
| return w; // OK since C++23 |
| } |
| |
| // ... or pointers. |
| int* five(Mutt x) { |
| return x; // OK since C++20 because P1155 |
| } |
| |
| int& six(Jeff x) { |
| return x; |
| } |
| |
| int test_ella(Ella e) { |
| return e; |
| } |
| |
| template<class T> |
| T&& seven(T&& x) { return x; } |
| |
| void test_seven(Widget w) { |
| Widget& r = seven(w); |
| Widget&& rr = seven(std::move(w)); |
| } |
| |
| Widget val(); |
| Widget& lref(); |
| Widget&& rref(); |
| |
| decltype(auto) eight() { |
| decltype(auto) x = val(); // OK, x is Widget |
| return x; // OK, return type is Widget, we get copy elision |
| } |
| |
| decltype(auto) nine() { |
| decltype(auto) x = lref(); // OK, x is Widget& |
| return x; // OK, return type is Widget& |
| } |
| |
| decltype(auto) ten() { |
| decltype(auto) x = rref(); // OK, x is Widget&& |
| // This was an error: return type is Widget&&, cannot bind to x. |
| // But in C++23, x is treated as an rvalue. |
| return x; |
| } |
| |
| // Now returns Widget&&, not Widget&. |
| // This is from $ 3.2.1. Interaction with decltype and decltype(auto). |
| decltype(auto) eleven(Widget&& x) { |
| return (x); |
| } |
| static_assert(same_type<decltype(eleven), Widget&& (Widget&&)>::value); |