Passing temporaries as non-const references in C++

2019-03-11 08:45发布

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?

3条回答
仙女界的扛把子
2楼-- · 2019-03-11 08:57

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.

查看更多
\"骚年 ilove
3楼-- · 2019-03-11 09:03

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.

查看更多
相关推荐>>
4楼-- · 2019-03-11 09:11

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.

查看更多
登录 后发表回答