C++0x const RValue ссылка в качестве параметра функции
Я пытаюсь понять, почему кто-то написал бы функцию, которая принимает константную ссылку.
В приведенном ниже примере кода для какой цели используется ссылочная функция const rvalue (возвращающая "3"). И почему разрешение перегрузки предпочитает const Rvalue выше справочной функции const LValue (возвращая "2").
#include <string>
#include <vector>
#include <iostream>
std::vector<std::string> createVector() { return std::vector<std::string>(); }
//takes movable rvalue
void func(std::vector<std::string> &&p) { std::cout << "1"; }
//takes const lvalue
void func(const std::vector<std::string> &p) { std::cout << "2"; }
//takes const rvalue???
//what is the point of const rvalue? if const I assume it is not movable?
void func(const std::vector<std::string> &&p) { std::cout << "3"; }
int main()
{
func(createVector());
return 0;
}
2 ответа
Lvalue настоятельно предпочитает привязку к ссылкам lvalue, и аналогично ссылки rvalue настоятельно предпочитают привязку к ссылкам rvalue. Изменяемые выражения слабо предпочитают привязку к неконстантной ссылке.
Поэтому, когда ваш компилятор выполняет разрешение перегрузки, он проверяет, есть ли перегрузка, которая принимает ссылку на rvalue, потому что это сильно предпочтительнее. В этом случае, так как эксперимент представляет собой изменяемое значение r, выигрывает эталонная перегрузка rvalue.
На самом деле есть использование для константных ссылок, они могут быть использованы для того, чтобы убедиться, что что-то не привязано к r-значению. Помните, что rvalue связывается с константной lvalue ссылкой, следовательно, если вы это сделали:
template <typename T> void foo(const T& bar) { /* ... */ }
И вызвал функцию с:
foo(createVector());
Это будет работать нормально. Однако иногда желательно убедиться, что вы можете передавать только значения l в функцию (это относится к std::ref
для одного). Вы можете добиться этого, добавив перегрузку:
template <typename T> void foo(const T&&) = delete;
Помните, что значения rvalue предпочитают привязку к ссылкам rvalue, а модифицируемые выражения предпочитают слабую привязку к неконстантным ссылкам. Поскольку у нас есть const rvalue-reference, это в основном означает, что каждое отдельное rvalue будет связываться с этим, следовательно, если вы попытаетесь передать rvalue в foo()
твой компилятор выдаст ошибку. Это единственный способ достичь такой функциональности, и поэтому иногда он полезен.
Разрешение перегрузки предпочитает const rvalue, а не const lvalue, потому что, в общем, это rvalue, и вы привязываете его к ссылке на rvalue, но вам нужно добавить const в обоих случаях, поэтому ссылка на rvalue определенно предпочтительнее.
Такие вещи, как правило, бессмысленны - лучше оставить их связанными с постоянными перегрузками. константные значения не имеют никакого реального использования.