2011-12-20 2 views
10

Предположим, что у меня есть два struct S:Совершенная пересылка элемента объекта

struct X {}; 
struct Y { X x; } 

У меня есть функции:

void f(X&); 
void f(X&&); 

Как написать функцию g(), которая принимает Y& или Y&& но идеальный переадресацию X& или X&& до f(), соответственно:

template <typename T> 
void g(T&& t) { 
    if (is_lvalue_reference<T>::value) { 
    f(t.x); 
    } else { 
    f(move(t.x)); 
    } 
} 

Приведенный выше код иллюстрирует мое намерение, но не очень масштабируемо по мере увеличения числа параметров. Есть ли способ заставить его работать для идеальной пересылки и сделать его масштабируемым?

+0

Я думаю, что изменение 'is_lvalue_reference :: value' к' is_lvalue_reference (т))> :: value' будет иметь семантику, которую вы хотите, но я думаю, что ваша желаемая семантика сомнительна ... – ildjarn

+0

(Извините за неудачный ответ.) Я бы сказал, что причина, по которой он не масштабируется, заключается в том, что дизайн сомнительный для начала. Что значит «переместить» подобъект? В каком состоянии это оставляет основной объект? Даже если бы был простой способ написать это, это выглядит плохо структурированный код ... –

ответ

15
template <typename T> 
void g(T&& t) { 
    f(std::forward<T>(t).x); 
} 
+1

выглядит хорошо для меня http://ideone.com/Edf4o –

+0

Многое лучшее решение, но почему именно он работает? – Pubby

+0

@ Пуби, потому что 'rvalue.foo' является rvalue. Я могу подумать, почему это может иметь смысл (если контейнер имеет короткое время жизни и является rvalue, содержащийся объект тоже разделяет это свойство), но я не знаком с философией и не знаю обоснования, поэтому я ничего не могу сказать об этом. –

3

Я думаю, что это будет работать, хотя я не уверен:

template<class T, class M> 
struct mforward { 
    using type = M&&; 
}; 
template<class T, class M> 
struct mforward<T&, M> { 
    using type = M&; 
}; 

template <typename T> 
void g(T&& t) { 
    f(std::forward<typename mforward<T, decltype(t.x)>::type>(t.x)); 
} 
+2

+1 Мне пришлось решить почти эту проблему в libC++. Решение, которое я придумал, выглядело очень похоже на Pubby's. Я не только «применил» l/r-ценность «T» к «M», я также хотел применить cv-квалификацию «T» к «M». И я нашел приложения для него вне членов данных. Для любопытных я назвал его '__apply_cv', и это открытый исходный код: http://libcxx.llvm.org/ –

+0

@Howard см. Мой ответ для альтернативы. Или мне что-то не хватает? –

+0

Также @Howard, говорящий о квалификации cv, заставляет меня думать о недостатке этого ответа. 'decltype (t.x)' только дает вам объявленный тип 'x'. Если 'T' является' const', но 'x' был объявлен как' int a', ваш forward будет пытаться пересылать вещи как 'int &'/'int &&'. Вам нужно будет сказать что-то вроде 'typename remove_reference :: type', чтобы учесть также константу' t'. Это также учитывает члены 'mutable', но я не знаю, что означает философский переход к изменяемому члену объекта' const'. –

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