10

我有以下代码,例如 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 实例——这似乎是一种非常混乱和有限的方法。

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

4

3 回答 3

14

听听斯蒂芬的建议,您应该看看如何非常量引用不能绑定到临时对象的答案?并简单地添加一个返回引用的成员函数dec_proxy,例如:

dec_proxy &ref() { return *this; }

并致电foo

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

我很确定可以编译。

于 2011-10-05T07:15:12.657 回答
7

感谢MSN,解决方案:

我认为通过添加功能模板是不正确的template<typename T> dec_proxy_impl<T>& dec_proxy(T&t)

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

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

于 2011-10-05T08:33:58.830 回答
2

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

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

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

但这只是问题的一部分。您尝试做的是预先增加一个临时值!这是胡说八道,因为它不会在那个电话之后存活。您的对象将被递增,然后被销毁。


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

于 2011-10-05T07:03:25.497 回答