2016-12-27 6 views
3

Вот два разных типа станд :: вектор, как пример:Как сравнить и назначить между std :: vector <T> и std :: vector <std :: reference_wrapper <T>>?

std::vector<std::reference_wrapper<MyClass>> rv; 
std::vector<MyClass> v; 

Возможный способ назначить между ними:

for (const auto& mc : rv) { 
    v.push_back(mc.get()); 
} 

Он работает. Но уродливый и, возможно, медленный. То же самое, что и сравнение:

bool is_same(std::vector<MyClass>& v, std::vector<std::reference_wrapper<MyClass>>& rv) { 
    if (v.size()!=rv.size()) { 
     return false; 
    } 
    for (size_t i = 0; i < v.size(); v++) { 
     if (v[i]!=rv[i].get()) { 
      return false; 
     } 
    } 
    return true; 
} 

Есть ли лучший способ для выполнения этой работы? Умный и быстрый.

ответ

5

Поскольку std::reference_wrapper неявно конвертируется в ссылку на его тип, вы можете назначить его MyClass. Так лучший способ инициализировать один с другой соответствующий вектор конструктор:

std::vector<MyClass> v(begin(rv), end(rv)); 

Или, если вам действительно нужно назначить:

v.assign(begin(rv), end(rv)); 

Вы можете сделать сравнение с применением алгоритма std::mismatch , опять-таки благодаря неявном предоставленной std::reference_wrapper:

bool is_same(std::vector<MyClass> const& v, std::vector<std::reference_wrapper<MyClass>> const& rv) { 
    return v.size() == rv.size() && 
     end(v) == std::mismatch(begin(v), end(v), begin(rv), end(rv)).first; 
} 

Как общее правило, это всегда полезно проконсультироваться со стандартной библиотекой алгоритмов, прежде чем писать петли самостоятельно. Это делает ваш собственный код более читаемым, предоставляя глаголы и существительные для шагов вычисления. И имеет преимущество, позволяя любые оптимизации, которые может предложить стандартная библиотека.


Как cppleaner указывал, я консультировался библиотеку более тесно себя. is_same может быть реализована еще более легко с помощью простого вызова std::equal

return std::equal(begin(v), end(v), begin(rv), end(rv)); 
+0

Я бы использовал 'std :: equal (begin (v), end (v), begin (rv), end (rv))', а не 'v.size() == rv.size() && end (v) == std :: mismatch (begin (v), end (v), begin (rv), end (rv)). first'. 'std :: equal' не только яснее, но и сохраняет одно сравнение итератора на каждой итерации. – cpplearner

+0

@cpplearner - Спасибо. Я не должен был писать этот ответ, прежде чем пить кофе. – StoryTeller

0

Идиоматические реализация is_same:

bool is_same(std::vector<MyClass>& v, std::vector<std::reference_wrapper<MyClass>>& rv) { 

    return std::equal(begin(v), end(v), begin(rv), end(rv), 
     [](const MyClass& c, const std::reference_wrapper<MyClass>& rc) { 

     return c == rc.get(); 
    }); 
} 

В качестве альтернативы, вы можете написать на заказ:

class MyClass { 
    bool operator ==(const MyClass&); 
}; 

bool operator != (const MyClass&, const MyClass&); 
bool operator == (const MyClass&, const std::reference_wrapper<MyClass>&); 
bool operator == (const std::reference_wrapper<MyClass>&, const MyClass&); 
bool operator != (const MyClass&, const std::reference_wrapper<MyClass>&); 
bool operator != (const std::reference_wrapper<MyClass>&, const MyClass&); 

и код клиента (это является избыточным: вы можете просто использовать реализацию в качестве операции):

bool is_same(const std::vector<MyClass>& v, 
      const std::vector<std::reference_wrapper<MyClass>>& rv) { 
    return v == rv; 
} 

Примечание: Рассмотрите возможность использования const на своих аргументах, где это возможно.

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

  • Нет связанных вопросов^_^