В чем преимущество использования универсальных ссылок в циклы на основе диапазона?
const auto&
было бы достаточно, если я хочу выполнять операции только для чтения. Однако я наткнулся на
for (auto&& e : v) // v is non-const
в последнее время пару раз. Это заставляет меня задуматься:
возможно ли, что в некоторых неясных угловых случаях есть некоторое преимущество в производительности при использовании универсальных ссылок по сравнению с auto&
или const auto&
?
(shared_ptr
является подозреваемым по неясным угловым делам)
обновление Два примера, которые я нашел в моем избранное:
любой недостаток использования ссылки const при итерации по основным типам?
могу ли я легко перебирать Значения карты, используя цикл for на основе диапазона?
пожалуйста, сосредоточьтесь на вопросе:почему я хочу использовать auto&& в диапазоне на основе петель?
3 ответа:
единственное преимущество, которое я вижу, это когда итератор последовательности возвращает ссылку прокси, и вам нужно работать с этой ссылкой неконстантным образом. Например рассмотрим:
#include <vector> int main() { std::vector<bool> v(10); for (auto& e : v) e = true; }
это не компилируется, потому что rvalue
vector<bool>::reference
вернулся изiterator
не будет привязываться к неконстантной ссылке lvalue. Но это будет работать:#include <vector> int main() { std::vector<bool> v(10); for (auto&& e : v) e = true; }
все, что было сказано, я бы не кодировал таким образом, если бы вы не знали, что вам нужно удовлетворить такой случай использования. То есть я бы этого не сделал безвозмездно, потому что это тут заставьте людей задаться вопросом,что вы делаете. И если бы я это сделал, не помешало бы включить комментарий о том, почему:
#include <vector> int main() { std::vector<bool> v(10); // using auto&& so that I can handle the rvalue reference // returned for the vector<bool> case for (auto&& e : v) e = true; }
Edit
этот последний мой случай должен действительно быть шаблоном, чтобы иметь смысл. Если вы знаете, что цикл всегда обрабатывает ссылку прокси, то
auto
будет работать так же хорошо, какauto&&
. Но когда цикл иногда обрабатывал не прокси-ссылки, а иногда прокси-ссылки, то Я думаюauto&&
станет оптимальным решением.
используя
auto&&
или универсальный ссылок с диапазоном на основеfor
-петля имеет то преимущество, что вы захватывает то, что вы получаете. Для большинства видов итераторов вы, вероятно, получите либоT&
илиT const&
для некоторого типаT
. Интересный случай заключается в том, что разыменование итератора дает временное: C++ 2011 получил смягченные требования, и итераторы не обязательно должны давать значение lvalue. Использование универсальных ссылок соответствует пересылке аргументов вstd::for_each()
:template <typename InIt, typename F> F std::for_each(InIt it, InIt end, F f) { for (; it != end; ++it) { f(*it); // <---------------------- here } return f; }
функции объекта
f
может относиться кT&
,T const&
иT
по-разному. Почему тело диапазона на основеfor
-цикл будет отличаться? Конечно, чтобы на самом деле воспользоваться выводом типа с использованием универсальных ссылок, вам нужно будет передать их соответственно:for (auto&& x: range) { f(std::forward<decltype(x)>(x)); }
конечно, с помощью
std::forward()
означает, что вы принимаете любые возвращенные значения для перемещения. Имеет ли такой объект большой смысл в не шаблонный код я не знаю (пока?). Я могу себе представить, что использование универсальных ссылок может предложить компилятору больше информации, чтобы сделать правильную вещь. В шаблонном коде он остается вне принятия какого-либо решения о том, что должно произойти с объектами.