Запретить указатель / ссылку на const для временного объекта в C ++ (без C ++ 0X) - PullRequest
8 голосов
/ 09 ноября 2010

Я столкнулся со следующей проблемой.Рассмотрим следующий класс:

//Will be similar to bost::reference_wrapper
template<class T>
class Ref {
public:
  explicit Ref(T& t) : m_ptr(&t) {}
private:
  T* m_ptr;
};

, и эта функция возвращает двойное значение

double fun() {return 1.0;}

Если у нас сейчас есть

double x = 1.0;
const double xc = 1.0;

Ref<double> ref1(x); //OK
Ref<const double> refc1(cx); //OK

хорошо, однако:

//Ref<double> ref2( fun() ); //Fails as I want it to
Ref<const double> refc2( fun() ); //Works but I would like it not to

Есть ли способ изменить Ref (так, как вы предпочитаете), но не функцию fun, чтобы последняя строка возвращала ошибку времени компиляции?Обратите внимание, что вы можете изменить сигнатуру конструктора (при условии, что я могу инициализировать Ref как задумано).

Ответы [ 4 ]

3 голосов
/ 09 ноября 2010

Нет, и ваш код может быть взломан даже при обычной ссылке. Просто задокументируйте тот факт, что переданный объект должен быть постоянным.

double *x = new double;
Ref<double> ref(*x);
delete x;    
2 голосов
/ 09 ноября 2010

Вам может не понравиться синтаксис, чтобы использовать его, но заставьте конструктор взять указатель вместо ссылки. Вы не можете взять даже временный указатель const.

По крайней мере, не без контрабанды через другую оболочку, которая, как мы надеемся, делает код Очевидно неправильным (TM): template <typename T> T *reftoptr(T &t) { return &t; }

Тем не менее, если вы используете этот способ, как reference_wrapper, ваши пользователи могут хотеть для захвата временных. Пока объект Ref также является временным в том же полном выражении, что и временный объект, который он захватывает, я думаю, что все в порядке. Так, например,

some_algorithm(iterator, anotherit, static_cast<Ref<const double> >(fun()));
1 голос
/ 09 ноября 2010

Используйте аргумент указателя для инициализации вашего члена указателя. Не используйте (const) ссылку для этого - используйте указатель для инициализации указателя.

В прошлом у меня были некоторые проблемы с отслеживанием ссылок, и хотя это не имеет прямого отношения к вашему вопросу, вам могут показаться интересными эти две темы:

0 голосов
/ 13 января 2011

Вы можете использовать шаблон.U& выводится в double&, и это не привязывается к rvalues.

template<class T>
class Ref {
public:
  template<typename U>
  explicit Ref(U& t, 
               typename boost::enable_if< 
                 boost::is_convertible<U, T&> 
               >::type * = 0) 
    : m_ptr(&t) {}
private:
  T* m_ptr;
};
...