Возвращает ссылку на значение rvalue, когда это возможно, или просто устаревший тип, когда это невозможно

#c

#c

Вопрос:

Я хочу разработать функцию разыменования для необязательных

Когда я даю ссылку lvalue на функцию, я хочу, чтобы возвращаемый тип был ссылкой на значение lvalue. (т. е. intamp; )

Когда я передаю временный объект (т. Е. prvalue) функции, я хочу, чтобы возвращаемый тип был устаревшим типом (т. Е. int )

Когда я передаю функции перемещенный объект (т. Е. xvalue), я хочу, чтобы возвращаемый тип был ссылкой на значение rvalue (т. е. intamp;amp; )

Я написал 2 функции :

 template<typename T>
decltype(auto) bad(T amp;amp;t) {
    return *fwd(t);   
}
  

Эта функция возвращает ссылку на значение rvalue, когда мы даем значение prvalue, и, таким образом, мы получаем висячую ссылку

 struct remove_rvalue_reference {
    using type = std::decay_t<T>;
};

template <typename T>
struct remove_rvalue_reference<T amp;> {
    using type = T amp;;
};

template <typename T>
using remove_rvalue_reference_t = typename remove_rvalue_reference<T>::type;

template<typename T>
auto good(T amp;amp;t) -> remove_rvalue_reference_t<decltype(*fwd(t))> {
    return *fwd(t);
}
  

Эта функция работает хорошо, но когда мы задаем значение x, мы получаем устаревший тип, но нам нужна ссылка на значение rvalue

Вот пример кода

 #include <optional>
#include <iostream>
#include <type_traits>
#define fwd(x) ::std::forward<decltype(x)>(x)

template <typename T>
struct remove_rvalue_reference {
    using type = std::decay_t<T>;
};

template <typename T>
struct remove_rvalue_reference<T amp;> {
    using type = T amp;;
};

template <typename T>
using remove_rvalue_reference_t = typename remove_rvalue_reference<T>::type;

template<typename T>
decltype(auto) bad(T amp;amp;t) {
    return *fwd(t);   
}

template<typename T>
auto good(T amp;amp;t) -> remove_rvalue_reference_t<decltype(*fwd(t))> {
    return *fwd(t);
}

int main() {
    std::optional<int> a = 5;
    
    // both are lvalue reference
    decltype(auto) aref = bad(a); // ok
    decltype(auto) aref2 = good(a); // ok
    
    static_assert(std::is_lvalue_reference_v<decltype(aref)>);
    static_assert(std::is_lvalue_reference_v<decltype(aref2)>);
    
    decltype(auto) arvref = bad(std::move(a)); // ok
    decltype(auto) arvref2 = good(std::move(a)); // not ok : not a rvalue reference -> lose perf
    
    static_assert(std::is_rvalue_reference_v<decltype(arvref)>);
    static_assert(!std::is_reference_v<decltype(arvref2)>);
    
    decltype(auto) rvref = bad(std::make_optional(5)); // NOT OK !! DANGLING REF
    decltype(auto) rvref2 = good(std::make_optional(5)); // OK
    
    static_assert(std::is_rvalue_reference_v<decltype(rvref)>);
    static_assert(!std::is_reference_v<decltype(rvref2)>);
}
  

Комментарии:

1. Я не думаю, что есть способ отличить prvalues от аргументов xvalue.

2. Это то, чего я боюсь…