【问题标题】:Determining if being passed a temporary确定是否通过临时
【发布时间】:2011-08-24 02:42:07
【问题描述】:

假设我有一个类 C 和一个创建 C 实例的函数 make_c(x)

C 通过引用存储x

x 是一个未命名的临时文件(这当然会在行尾破坏,留下一个悬空引用)但接受命名临时文件和其他值时,我如何编写make_c(x) 以给出编译错误?

【问题讨论】:

  • @Potatoswatter:我的意思是const T& x = f()x 是一个命名的临时文件(它不会在行尾被销毁)。
  • @Clinton:这不会在行尾破坏。当x 超出范围时,它会被销毁。
  • @Clinton 那么这不是暂时的。
  • @Nawaz:这不是我说的吗?
  • @Clinton:您所做的任何事情(无论如何都不是合法的 C++)要求您“识别未命名的临时人员”。事实上,C++0x 语言让你几乎不可能这样做,而且他们费尽心思阻止它可能有一个很好的理由。

标签: c++ c++11


【解决方案1】:

我相信这应该具有您正在寻找的语义:

template<typename X>
C make_c(X&& x)
{
    static_assert(
        !std::is_rvalue_reference<decltype(std::forward<X>(x))>::value,
        "x must not be a temporary"
    );
    return C(std::forward<X>(x));
}

警告:由于在 decltype 的实现中存在缺陷,这将无法在 VC++ 2010 中按原样工作(您需要将 decltype 包装在 std::identity&lt;&gt; 中)。

【讨论】:

  • 你能补充一些关于各个部分在这里做什么的解释吗?特别是需要std::forward&lt;X&gt; 和需要明确的X 相同吗? (有时我认为所有 C++0x“右值引用”的东西对我来说都毫无意义。)
  • @ildjarn:这在T&amp;&amp; x = f() 的情况下是否有效(大概也延长了 f() 的生命周期,所以应该接受)?
  • @Nemo:在此处查找有关“完美转发”的问题。
  • @Nemo :解释右值引用折叠的规则远远超出了这个问题的范围。如果您发现它们令人困惑,则很可能需要就该主题提出适当的问题,以寻求深入的答案。 :-]
  • @Clinton :首先,是的,T&amp;&amp; x = f(); 延长了 f() 返回的临时变量的生命周期(参见 §8.5.3/5 和 §12.2/5)。其次,不,此代码在这种情况下不起作用(而且我认为不可能区分两者,就像无法区分 const&amp; 临时和 const&amp; 非临时C++03);但是,我个人认为大多数利用“最重要的const”的代码将使用const 左值引用,因为与任何与右值引用相关的习语相比,这是一种相当容易理解和成熟的做法。
【解决方案2】:

我认为这在语言中是不可能的,因为您需要通过任意函数检查流控制。

struct Foo{
};

Foo const & sanitize(Foo const & f){ return f;}

void checkThisFunction(Foo const & f){
   //we'd like to ensure at compile time that f is not a temporary
}

int main(){
   Foo f;
   checkThisFunction(sanitize(f));
   checkThisFunction(sanitize(Foo()));
   return 0;
}

【讨论】:

  • 那么该代码示例是否有效?从您的回答中(对我来说)不清楚。
  • 这是在 C++ 中工作的代码示例,但无法检查传递给 checkThisFunction 的 Foo 是否不是临时的。
  • @Ken:我很高兴checkThisFunction(sanitize(f))checkThisFunction(sanitize(Foo())) 都被拒绝了。我只希望checkThisFunction(f) 被接受,const Foo&amp; f = Foo(), checkThisFunction(f)
  • @Clinton:他非常清楚地说你无法区分。您不能使用 r 值引用和 const-l 值引用的任意组合优先过滤掉这些可能性。如果checkThisFunction(f) 有效,那么checkThisFunction(sanitize(f)) 必须 也有效。
  • @Nicol:但他可能会编写一个 GCC 插件(或 Dehydra 或 TreeHydra 插件)来对这个特定功能执行类似 lint 的检查。但我不太了解如何做到这一点。
【解决方案3】:

除非我完全误解了右值引用,否则这种事情应该可以通过简单的重载来实现。

void foo(int&&) = delete;
void foo(const int&) { }

int main()
{
   int a;
   foo(a);
   foo(42);  //error, prefers binding to the deleted overload
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-11
    • 2020-05-13
    • 2018-08-22
    • 1970-01-01
    • 2021-12-25
    • 1970-01-01
    相关资源
    最近更新 更多