Передача временных значений как неконстантных ссылок в C ++ - PullRequest
9 голосов
/ 05 октября 2011

У меня есть следующий фрагмент кода, в качестве примера 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 - это выглядит очень грязным и ограниченным подходом.

Мой вопрос: как правильно передать такие кратковременные временные значения в качестве неконстантных опорных параметров?

Ответы [ 3 ]

12 голосов
/ 05 октября 2011

Следуя совету Стивена, вы должны посмотреть на ответ на Почему неконстантная ссылка не может привязаться к временному объекту? и просто добавить функцию-член, которая возвращает ссылку dec_proxy, например:

dec_proxy &ref() { return *this; }

и вызов foo:

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

Я почти уверен, что компилируется.

7 голосов
/ 05 октября 2011

Благодаря 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) не возвращает действительную ссылку lvalue. В реализации он создает временный объект и возвращает его. После завершения вызова функции временный объект будет уничтожен. Поэтому ссылка на значение, переданная в функцию foo, неверна. Фактически указанный объект уже был уничтожен. ++t;++s;++r пытается получить доступ к недопустимым объектам. Поведение не определено.

Решение от MSN правильное. Время жизни объекта dec_proxy<int>(i) от его объявления до конца вызова функции. Он гарантирует, что параметр в функции foo действителен.

2 голосов
/ 05 октября 2011

То, что вы пытаетесь сделать, это передать rvalue (ваше new dec_facade<int>(i)) в качестве ссылки lvalue, что объясняет, почему оно не работает.

Если вы поддерживаете его компилятор, вы можете использовать ссылки rvalueс использованием && модификатора типа: (Поддержка ссылки на rvalue может быть включена путем включения поддержки C ++ 0x или C ++ 11 [частичная])

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

Но это только одна часть проблемы,Что вы пытаетесь сделать, это предварительно увеличить временное значение!Это бессмысленно, так как он не будет жить после этого звонка.Ваш объект будет увеличиваться, а затем уничтожаться.


Еще одно решение - удалить & из определения вашей функции, что позволит ему принимать любой параметр.Но это, возможно, не то, что вы хотите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...