2015-04-21 5 views
2

Подобно this question, но вместо идеального члена экспедиционного объекта, я хотел бы знать, как усовершенствовать экспедиционные элементы контейнера STL, т.е. похожи наИдеальных экспедиторская элемент контейнера

struct X {}; 
void f(X&); 
void f(X&&); 

template <typename Vector> 
void g(Vector&& v, size_t i) { 
    if (is_lvalue_reference<Vector>::value) { 
    f(v[i]); 
    } else { 
    f(move(v[i])); 
    } 
} 
+0

Можете ли вы привести пример того, что вы пытаетесь сделать? – Barry

+0

@ Барри, я последовал за правилом http://sscce.org/, чтобы обрезать его до минимума. Фактический прецедент сложный. Я хотел бы создать 'vector ' from 'vector ', 'vector ', ...., где каждый элемент 'T' построен из' U1', 'U2', .... Каждый массив из 'vector ' может быть либо & или &&, и я бы хотел, чтобы 'Ui' был отлично переадресован. –

+1

Что-то вроде http://coliru.stacked-crooked.com/a/8aadafc70b8c979b? –

ответ

6
namespace detail { 
    template<class T, class U> 
    using forwarded_type = std::conditional_t<std::is_lvalue_reference<T>::value, 
               std::remove_reference_t<U>&, 
               std::remove_reference_t<U>&&>; 
} 
template<class T, class U> 
detail::forwarded_type<T,U> forward_like(U&& u) { 
    return std::forward<detail::forwarded_type<T,U>>(std::forward<U>(u)); 
} 

template <typename Vector> 
void g(Vector&& v, size_t i) { 
    f(forward_like<Vector>(v[i])); 
} 

Demo , Использование std::forward в реализации автоматически предотвращает выполнение опасного перехода от rvalue как lvalue.

Для вашего фактического случая использования

Я хотел бы создать vector<T> из vector<U1>, vector<U2>, ...., где каждый элемент T строится из U1, U2, .... Каждый массив из vector<Ui> может быть & или &&, и я хотел бы, чтобы Ui был отлично переправлен.

это становится чем-то вроде

template<class T, class...Vectors> 
std::vector<T> make_vector(Vectors&&...vectors){ 
    auto n = std::min({vectors.size()...}); 
    std::vector<T> ret; 
    ret.reserve(n); 
    for(decltype(n) i = 0; i < n; ++i) 
     ret.emplace_back(forward_like<Vectors>(vectors[i])...); 
    return ret; 
} 
+0

Итак, если у нас есть ссылка на набор значений rvalue кортежа lvalue, следует «forward_like» (get_tuple_member (t)) 'return rvalue или lvalue? Я думаю, мы не можем отличить «член» от «ссылочного элемента» от функции доступа. Может быть, мы должны делать 'std :: forward (v) [i]' и 'vector :: operator []' должна иметь перегрузку rvalue? Hurm. Теоретически 'std :: forward (foo) .field' - это то, что мы стремимся подражать здесь, нет? – Yakk

+0

@Yakk Да, поэтому пересылка ссылочного элемента lvalue кортежа rvalue должна давать lvalue. (Я считаю, что 'std :: get' уже обрабатывает его?) –

+0

* nod *, но выше не может: единственный способ сделать это - быть« внутри »класса и знать, есть ли у вас' T' или ' T & ', так как любой разумный аксессуар будет возвращать' T & 'в обоих случаях. Я просто замечал, что если бы у вас был (несуществующий) 'vector ', то выше было бы «перемещаться», если бы контейнер был rvalue и думал, есть ли способ обойти его. Я его не вижу. Делает 'forward_like ' более слабым, чем rvalue-аксессоры, в основном. И доступным для доступа к rvalue устройствам всегда казалось, что они грязные (вам нужно знать, что вы не очень * двигаетесь, просто перемещая это одно поле). – Yakk

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