Является ли он корректным, чтобы передать значения xvalues ​​в lvalues ​​для перехода к функциям?

Недавно я обнаружил что иногда возможность временного превращения rvalues ​​в lvalues ​​может быть полезно для меня.

Я использовал следующий инструмент:

#include <type_traits>

template <typename T>
inline constexpr std::remove_reference_t<T> &lvalue(T &&r) noexcept {
    return static_cast<std::remove_reference_t<T> &>(r);
}

Это полезно, когда вам нужно использовать функции, которые требуют lvalues ​​как аргументы, но у вас нет интереса к тому, что значения меняются. Если вас интересует другой выход векторы, которые не связаны с заданным конкретным аргументом.

Например, это:

std::string get_my_file() {
    std::ifstream ifs("myfile.txt");
    return {std::istreambuf_iterator<char>(ifs), {}};
}

можно изменить на это:

std::string get_my_file() {
    return {std::istreambuf_iterator<char>(lvalue(std::ifstream("myfile.txt"))),
            {}};
}

И это:

std::string temp1 = get_my_shader();
const char *temp2 = temp1.c_str();
glShaderSource(a, 1, &temp2, nullptr);

можно изменить на это:

glShaderSource(a, 1, &lvalue(get_my_shader().c_str()), nullptr);

И разрешите такие вещи:

void foo(int *x) {
    std::cout << *x << std::endl;
}

foo(&lvalue(5));

Я хотел бы быть уверенным, что я вызываю undefined -behavior или нет ни в одном из них, потому что я его не вижу, хотя может быть какое-то правило кастинга, которое превратило бы его в незаконное (что я игнорировать). Что касается времени жизни временных рядов, я не вижу проблемы, поскольку AFAIK, rvalues ​​живут до конца полного выражения, и использование функции ограничено этим.

Недавнее изменение стандарта о reinterpret_cast и xvalues это похоже на тему:

qaru.site/info/382539/...

ИЗМЕНИТЬ

Лучшая версия, использующая обращение с рекомендациями:

template <typename T>
constexpr T &lvalue(T &&r) noexcept { return r; }

Ответы

Ответ 1

Как вы сказали, вы позаботились о том, чтобы не допустить, чтобы какой-либо указатель или ссылка на временные ресурсы не отображались. Использование вашей lvalue -функции (моя называется no_move) облегчает непредсказуемость этого строя.

Затем посмотрим, что xvalues: Истекающие объекты, но объекты все же.
Это означает, что вы можете игнорировать их на похоронах (если вы передадите их функции, эта функция, естественно, сделает это, если вы не попросите воспользоваться).

Последнее, что вы упомянули, это вызов с prvalue, который, безусловно, не является объектом.
Но даже это не проблема, так как при вызове функции создается временная. И это временное, естественно, также сохранится до конца заявления.

В стороне, используя std::remove_reference_t<T>&, не требуется для возвращаемого типа lvalue, вы можете напрямую использовать T& и полагаться на правила сложения-сбрасывания. Кроме того, static_cast и inline являются излишними.

template <typename T> constexpr T& lvalue(T&& r) noexcept {return r;}