【问题标题】:Is it well-defined to cast xvalues to lvalues for passing to functions?将 xvalues 转换为 lvalues 以传递给函数是否定义明确?
【发布时间】:2015-01-19 02:42:25
【问题描述】:

Recently I've discovered 有时能够临时将右值转换为左值 对我有用。

我一直在使用以下工具:

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

我想确定我是否在其中任何一个中调用 undefined-behavior,因为我没有看到任何内容,尽管可能有一些强制转换规则会使其非法(我忽略) .关于临时人员的生命周期,我没有看到任何问题,因为 AFAIK,rvalues live until the end of full-expression 并且函数的使用仅限于此。

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

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

编辑

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

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

【问题讨论】:

  • 你很好。通过将 xvalues 转换为 lvalues 可以更容易搞砸的唯一事情是生命周期问题,而且你是对的,你的示例中没有危险,因为在创建它的语句之外没有引用临时文件。 (reinterpret_cast-proposal 实际上并未涉及您的问题。)
  • @Deduplicator 谢谢,我说的是右值而不是专门的 xvalue,因为这个问题还包括像 &amp;lvalue(5) 这样的表达式。顺便说一句,它工作正常。
  • 顺便说一句:你为​​什么使用std::remove_reference_t 而不是引用折叠规则?
  • 传递纯右值有效,因为它被复制到一个临时值,该临时值通过 xvalue-reference 传递给您的函数,并且该临时值只会在完整表达式的末尾被销毁,就像其余部分一样.关于简洁的改进:返回值而不是std::remove_reference_t&lt;T&gt; &amp;T&amp;。顺便说一句:我打电话给我的no_move,它对默认参数也很有用。
  • @pepper_chico:是的。顺便说一句:static_cast 也是多余的。

标签: c++ c++11 language-lawyer undefined-behavior c++14


【解决方案1】:

正如您所说,您注意不要让任何指向临时对象的指针或引用超出其范围。
使用你的lvalue-function(我的叫做no_move)可以更容易地在不经意间打破这种限制。

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

您提到的最后一点是使用纯右值调用,它肯定不是对象。
但即使这样也不是问题,因为在调用函数时,会创建一个临时的。
而那个临时的,自然也能活到语句结束。

顺便说一句,lvalue 的返回类型不需要使用std::remove_reference_t&lt;T&gt;&amp;,您可以直接使用T&amp; 并依赖引用折叠规则。另外,static_castinline 是多余的。

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

【讨论】:

    猜你喜欢
    • 2023-03-27
    • 1970-01-01
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-21
    相关资源
    最近更新 更多