在 C++ 中将临时变量作为非常量引用传递;

发布于 2024-12-08 09:30:52 字数 1026 浏览 1 评论 0原文

我有以下代码片段,例如 dec_proxy 尝试反转增量运算符对复杂函数调用 foo 中执行的类型的影响 - 顺便说一句,我无法更改其接口。

#include <iostream>

template<typename T>
class dec_proxy
{
public:
   dec_proxy(T& t)
   :t_(t)
   {}

   dec_proxy<T>& operator++()
   {
      --t_;
      return *this;
   }

private:
   T& t_;
};

template<typename T, typename S, typename R>
void foo(T& t, S& s, R& r)
{
  ++t;
  ++s;
  ++r;
}

int main()
{
   int i = 0;
   double j = 0;
   short  k = 0;

   dec_proxy<int> dp1(i);
   dec_proxy<double> dp2(j);
   dec_proxy<short> dp3(k);

   foo(dp1,dp2,dp3);

   //foo(dec_proxy<int>(i),     <---- Gives an error
   //   dec_proxy<double>(j),     <---- Gives an error
   //   dec_proxy<short>(k));      <---- Gives an error 

   std::cout << "i=" << i << std::endl;

   return 0;
}

问题是,对于我想使用 dec_proxy 的各种类型,我当前需要创建 dec_proxy 的专门实例 - 这似乎是一种非常混乱且有限的方法。

我的问题是:将这种短暂的临时变量作为非常量引用参数传递的正确方法是什么?

I have the following piece of code, as an example dec_proxy attempts to reverse the effects of the increment operator upon the type that is executed in a complex function call foo - which btw I cannot change the interface of.

#include <iostream>

template<typename T>
class dec_proxy
{
public:
   dec_proxy(T& t)
   :t_(t)
   {}

   dec_proxy<T>& operator++()
   {
      --t_;
      return *this;
   }

private:
   T& t_;
};

template<typename T, typename S, typename R>
void foo(T& t, S& s, R& r)
{
  ++t;
  ++s;
  ++r;
}

int main()
{
   int i = 0;
   double j = 0;
   short  k = 0;

   dec_proxy<int> dp1(i);
   dec_proxy<double> dp2(j);
   dec_proxy<short> dp3(k);

   foo(dp1,dp2,dp3);

   //foo(dec_proxy<int>(i),     <---- Gives an error
   //   dec_proxy<double>(j),     <---- Gives an error
   //   dec_proxy<short>(k));      <---- Gives an error 

   std::cout << "i=" << i << std::endl;

   return 0;
}

The problem is that for the various types I'd like to use dec_proxy I currently require creating a specialized instance of dec_proxy - it seems like a very messy and limited approach.

My question is: What is the correct way to pass such short-lived temporaries as non-const reference parameters?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

赠意 2024-12-15 09:30:52

采纳斯蒂芬的建议,您应该查看 为什么非常量引用不能绑定到临时对象? 只需添加一个返回引用的成员函数dec_proxy,例如:

dec_proxy &ref() { return *this; }

并调用 foo

foo(
    dec_proxy<int>(i).ref(), 
    dec_proxy<double>(j).ref(), 
    dec_proxy<short>(k).ref());

我很确定可以编译。

Taking Stephen's advice, you should look at the answer to How come a non-const reference cannot bind to a temporary object? and simply add a member function that returns a reference dec_proxy, e.g.:

dec_proxy &ref() { return *this; }

and call foo:

foo(
    dec_proxy<int>(i).ref(), 
    dec_proxy<double>(j).ref(), 
    dec_proxy<short>(k).ref());

I'm pretty sure that compiles.

迟月 2024-12-15 09:30:52

感谢 MSN,解决方案:

我认为通过添加函数模板 template是不正确的dec_proxy_impl& dec_proxy(T&t)

它所做的只是欺骗编译器。它将导致运行时错误。函数 foo 需要 lvaue 或左值引用。但是 templatedec_proxy_impl& dec_proxy(T&t) 不返回有效的左值引用。在实现中,它创建一个临时对象并返回它。函数调用完成后,临时对象将被销毁。因此传递给函数foo的值引用是错误的。实际上引用的对象已经被销毁了。 ++t;++s;++r 正在尝试访问无效对象。该行为是未定义的。

MSN的解决方案是正确的。对象dec_proxy(i)的生​​命周期是从其声明到函数调用结束。它确保函数 foo 中的参数有效。

Thanks to MSN, the solution:

I don't think it is correct by adding the function template template<typename T> dec_proxy_impl<T>& dec_proxy(T&t).

What it did is just cheating compiler. It will result in runtime error. The function foo requires the lvaue or lvalue reference. But template<typename T> dec_proxy_impl<T>& dec_proxy(T&t) doesn't return a valid lvalue reference. In the implementation, it creates a temporary object, and returns it. After the function call finishes, the temporary object will be destroyed. So the value reference passed into the function foo is wrong. Actually the referenced object has already been destroyed. The ++t;++s;++r are trying to access the invalid objects. The behavior is undefined.

The solution from MSN is correct. The life time of the object dec_proxy<int>(i) is from its declaration to the end of the function call. It makes sure the parameter in the function foo is valid.

忘你却要生生世世 2024-12-15 09:30:52

您尝试做的是将右值(您的 new dec_facade(i))作为左值引用传递,这解释了为什么它不起作用。

如果编译器支持它,您可以使用右值引用,使用 && 类型修饰符:
(可以通过打开 C++0x 或 C++11 [部分] 支持来启用对右值引用的支持)

template<typename T>
void foo(T& t)
{    
    ++t;
}
template<typename T>
void foo(T&& t)
{    
    ++t;
}

但这只是问题的一部分。您尝试做的是预先增加一个临时值!这是无意义的,因为在调用之后它就不会存在。你的对象将被增加,然后被销毁。


另一种解决方案是从函数定义中删除 & ,这将允许它接受任何参数。但这也许不是您想要的。

What you try to do is to pass a rvalue (your new dec_facade<int>(i)) as an lvalue reference, which explains why it doesn't work.

If you compiler support it, you can use rvalue references, using && type modifier :
(Support for rvalue reference could be enabled by switching on C++0x or C++11 [partial] support)

template<typename T>
void foo(T& t)
{    
    ++t;
}
template<typename T>
void foo(T&& t)
{    
    ++t;
}

But that only one part of the problem. What you try to do, is to pre-increment a temporary value! That's non-sense, as it won't live after that call. Your object will be increment, then destroyed.


One other solution would be to remove the & from your function definition, which would permit it to accept any parameter. But that's perhaps not what you want.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文