Передача временных значений как неконстантных ссылок в 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;
}
Но это только одна часть проблемы. Что вы пытаетесь сделать, это предварительно увеличить временное значение! Это бессмысленно, так как он не будет жить после этого звонка. Ваш объект будет увеличиваться, а затем уничтожаться.
Еще одно решение было бы удалить &
из определения вашей функции, что позволит ему принять любой параметр. Но это, возможно, не то, что вы хотите.