2017-02-01 3 views
2

Я хотел бы иметь функцию-член, которая принимает как левую, так и правую ссылки на некоторый класс и перемещает его объект. В настоящее время у меня есть две отдельные функции:Как принять как правую, так и левую ссылки в C++?

void ThrSafeQueue::push(Obj&& x) { 
    lock_guard(mutex_); 
    queue_.push(x); 
} 
void ThrSafeQueue::push(Obj& x) { 
    lock_guard(mutex_); 
    queue_.push(std::move(x)); 
} 
+7

Они называются ссылками lvalue и rvalue. –

+1

Примечание для 1-го случая вы также должны называть 'std :: move', примечание' x' является именованной переменной, таким образом, lvalue. – songyuanyao

+1

@ user1810087 Просто примечание, теперь они теперь называются пересылкой ссылок на стандарт. – NathanOliver

ответ

1

Первый вариант заключается в использовании шаблона функции-члена (forwarding references), но она не может быть виртуальным и может принимать некоторые другие типы вместо Obj в некоторых случаях:

template <typename T> 
void ThrSafeQueue::push(T&& x) { 
    lock_guard(mutex_); 
    queue_.push(std::move(x)); 
} 

Второй вариант - оставить только функцию, принимающую правильную ссылку, и static_cast<Obj&&> все левые ссылки. Вместо static_cast вы можете использовать std::move:

ThrSafeQueue t; 
t.push(Obj{}); 
Obj o; 
t.push(std::move(o)); 
+0

Обратите внимание, что вы можете использовать SFINAE для ограничения функции шаблона. Также ссылки называются ссылками lvalue и rvalue. – NathanOliver

4

Это то, что универсальный справочник для:

template<typename T> 
void ThrSafeQueue::push(T && x) { 
    lock_guard(mutex_); 
    queue_.push(std::forward<T>(x)); 
} 

Синтаксис кажется обманчивым. Здесь && фактически не обозначает ссылку rvalue, а universal reference, которая будет связываться с lvalue или rvalue, в зависимости от вызова шаблона.

std::forward будет, в зависимости от того, является ли его шаблон значением rvalue на lvalue, либо вырождается до std::move, либо нет-op в случае lvalue, именно то, что вы хотите.

Этот пример на самом деле попытается переправить что-либо, а не только Obj, до push(). Вероятно, это нормально, но если вы хотите ограничить вызов шаблона, который будет использоваться только с Obj s, при необходимости можно использовать обычные трюки с участием std::enable_if и std::is_same.

+5

Термин «универсальная ссылка» устарел. Вместо этого используйте ссылку «пересылка» –

Смежные вопросы