是否定义了将xvalues转换为左值以传递给函数?

pep*_*ico 14 c++ undefined-behavior language-lawyer c++11 c++14

最近我发现 ,有时能够将rvalues 暂时变成左值对我来说很有用.

我一直在使用以下工具:

#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);
}
Run Code Online (Sandbox Code Playgroud)

当您必须使用需要左值作为参数的函数时,它很有用,但您对这些特定值的变化没有任何兴趣.当您对与给定的特定参数无关的其他输出向量感兴趣时.

例如,这个:

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

可以改为:

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

还有这个:

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

可以改为:

glShaderSource(a, 1, &lvalue(get_my_shader().c_str()), nullptr);
Run Code Online (Sandbox Code Playgroud)

并允许这样的事情:

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

foo(&lvalue(5));
Run Code Online (Sandbox Code Playgroud)

我想确定我是否在调用任何未定义的行为,因为我没有看到任何行为,尽管可能会有一些转换规则将其视为非法(我忽略).关于临时的生命,我没有看到问题,因为AFAIK,rvalues直到完全表达结束并且函数的使用仅限于此.

有一个最近约标准的变化reinterpret_castxvalues 这似乎是在题目:

/sf/answers/1875538311/

编辑:

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

template <typename T>
constexpr T &lvalue(T &&r) noexcept { return r; }
Run Code Online (Sandbox Code Playgroud)

Ded*_*tor 9

正如你所说,你注意不要让任何指针或对临时工具的引用逃脱它们的范围.
使用你的lvalue函数(我的函数被调用no_move)可以更容易地在不经意间打破这种限制.

接下来,让我们看看是什么xvalues:过期对象,但对象.
这意味着,你可以忽略他们正在参加他们的葬礼之旅(如果你把它们传递给一个函数,那个函数自然会这样做,除非你要求利用).

你提到的最后一点是使用prvalue调用,这肯定不是一个对象.
但即使这不是问题,因为在调用函数时,会创建一个临时函数.
而那个临时性自然也会存在到声明的最后.

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

template <typename T> constexpr T& lvalue(T&& r) noexcept {return r;}
Run Code Online (Sandbox Code Playgroud)