Передача временных значений как неконстантных ссылок в C++

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

Решение

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

dec_proxy &ref() { return *this; }

и позвонить foo:

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

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

Благодаря 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 действителен.

Что вы пытаетесь сделать, это передать 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;
}

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


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

Другие вопросы по тегам