С++ rvalue reference и константный определитель
Среди многих преимуществ сотенной квалификации - сделать API более понятным, например:
template<typename T> int function1(T const& in);
// clearly, the input won’t change through function1
С введением ссылок rvalue можно получить отличную переадресацию, но часто удаляются конструкторы const, например:
template<typename T> int function2(T&& in);
// can explicitly forward the input if it an rvalue
Помимо документации, есть ли хороший способ описать, что функция2 не изменит свой вход?
Ответы
Ответ 1
template<typename T> int function2(T&& in);
// can explicitly forward the input if it an rvalue
Помимо документации, есть ли хороший способ описать это функция2 не изменит свой вход?
Да. Придерживайтесь решения С++ 03:
template<typename T> int function1(T const& in);
// clearly, the input won’t change through function1
Преимущества совершенной пересылки - это то, что вы не хотите предполагать, что что-то есть const
или не const
, lvalue или rvalue. Если вы хотите, чтобы что-то не было изменено (т.е. Оно const
), тогда явным образом скажу это, добавив const
.
Вы можете сделать это:
template<typename T> int function1(T const&& in);
// clearly, the input won’t change through function1
Однако все, кто читает ваш код, задаются вопросом, почему вы использовали ссылки rvalue. И function1
перестало бы принимать lvalues. Просто используйте const &
, и все поймут. Это простая и понятная идиома.
Вы не хотите идеально продвигаться вперед. Вы хотите обеспечить неизменность.
Ответ 2
Вы могли бы сказать следующее:
template <typename T>
typename std::enable_if<immutable<T>::value, int>::type
function(T && in)
{
// ...
}
где у вас есть что-то вроде:
template <typename T> struct immutable
: std::integral_constant<bool, !std::is_reference<T>::value> {};
template <typename U> struct immutable<U const &>
: std::true_type {};
Таким образом, шаблон будет использоваться только в том случае, если универсальная ссылка является либо константной ссылкой (so T = U const &
), либо ссылкой rvalue (поэтому T
не является ссылкой).
Тем не менее, если аргумент не будет изменен, вы можете просто использовать T const &
и сделать с ним, так как ничего не может быть связано с привязкой к временным значениям.