是否明确定义将 x值转换为左值以传递给函数

Is it well-defined to cast xvalues to lvalues for passing to functions?

本文关键字:函数 转换 定义 是否      更新时间:2023-10-16

最近我发现有时能够暂时将右值转换为左值可能是对我有用。

我一直在使用以下工具:

#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);
}

当您必须使用需要左值的函数时,它很有用论点,但你对这些特定的内容没有任何兴趣值更改为。当您对其他输出感兴趣时与给定特定参数无关的向量。

例如,这个:

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));

我想确定我是否在其中调用未定义的行为,因为我没有看到任何行为,尽管可能有一些铸造规则会将其变成非法(我忽略了)。关于临时的生命周期,我认为没有问题,因为 AFAIK,右值一直存在到完全表达结束,并且函数的使用仅限于此。

最近关于reinterpret_castxvalues的标准发生了变化这似乎是主题:

https://stackoverflow.com/a/26793404/1000282

编辑

建议使用引用折叠的更好版本:

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

正如你所说,你注意不让任何指向临时者的指针或引用逃脱他们的范围。
使用你的lvalue函数(我的函数叫做no_move)可以更容易地无意中打破这种限制。

接下来,让我们看看xvalues是什么:即将过期的对象,但对象仍然。
这意味着,您可以忽略它们正在参加葬礼(如果您将它们传递给某个函数,该函数自然会这样做,除非您要求利用)。

你提到的最后一点是使用 prvalue 调用,它肯定不是一个对象。
但即使这样也不是问题,因为在调用函数时,将创建一个临时函数。
而这个暂时性自然也会一直活到声明结束。

顺便说一句,对于返回类型的lvalue,使用std::remove_reference_t<T>&是不必要的,您可以直接使用T&并依赖于引用折叠规则。此外,static_castinline是多余的。

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