Я переключал функции фабрики шаблонов, чтобы использовать (и понимать) std :: forward для поддержки значений и перемещения семантики. Мои обычные фабричные функции для шаблонных классов всегда отмечали параметры как const:
#include <iostream>
#include <utility>
template<typename T, typename U>
struct MyPair{
MyPair(const T& t, const U& u):t(t),u(u){};
T t;
U u;
};
template<typename T, typename U>
std::ostream& operator<<(std::ostream& os, const MyPair<T,U>& pair){
os << "(" << pair.t << ")=>" << pair.u;
return os;
}
template<typename T, typename U>
MyPair<T,U> MakeMyPair(const T& t, const U& u){
return MyPair<T,U>(t,u);
}
using namespace std;
int main(int argc, char *argv[]) {
auto no_forward = MakeMyPair(num, num);
std::cout << no_forward << std::endl;
auto no_forward2 = MakeMyPair(100, false);
std::cout << no_forward2 << std::endl;
}
Компилируется как ожидалось. Сначала я преобразовал MakeMyPair, чтобы также передать параметры как const, но это не скомпилируется на моем Mac с использованием XCode 4.6:
//$ clang --version
//Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
//Target: x86_64-apple-darwin12.2.0
//Thread model: posixtemplate<typename T, typename U>
MyPair<T,U> MakeMyPair_Forward(const T&& t, const U&& u){
return MyPair<T,U>(std::forward<const T>(t),std::forward<const U>(u));
}
int main(int argc, char *argv[]) {
int num = 37;
auto anotherPair = MakeMyPair_Forward(num, true); //This won't work
auto allRvalues = MakeMyPair_Forward(73, false); //will compile
std::cout << allRvalues << std::endl;
}
Нет подходящей функции для вызова кандидата ‘MakeMyPair_Forward’
функция [с T = int, U = bool] нежизнеспособна: не известно преобразование из
‘int’ to ‘const int &&для первого аргумента
Это имеет смысл от http://en.cppreference.com/w/cpp/utility/forward который констант выводится и я передаю lvalue.
- Если вызов wrapper () передает rvalue std :: string, то T выводится в std :: string (не std :: string&, const std :: string&, или же
станд :: строка&&), и std :: forward гарантирует, что ссылка на rvalue
перешел в фу.- Если вызов wrapper () передает const lvalue std :: string, то T выводится в const std :: string&и std :: forward гарантирует, что const
Ссылка lvalue передается в foo.- Если вызов функции wrapper () передает неконстантное lvalue std :: string, то T выводится в std :: string&и std :: forward гарантирует, что неконстантный
Ссылка lvalue передается в foo.
Удаление const работает как я хочу с rvalues и lvalues. Только передача значений в качестве типов будет работать с const для параметров MakeMyPair_Forward.
//This works for rvalues and lvalues
template<typename T, typename U>
MyPair<T,U> MakeMyPair_Forward(T&& t, U&& u){
return MyPair<T,U>(std::forward<const T>(t),std::forward<const U>(u));
}
Итак, вопрос. Имеет ли смысл помечать ссылку на rvalue как const при передаче в качестве параметра? Я не могу изменить значение, это просто временно. Я был немного удивлен, что он скомпилирован с const после проработки и исправления моего кода. Почему вы должны пометить параметр rvalue как const? Будет ли смысл предоставлять только API, который принимает значения? Если так, разве вы не использовали бы вместо этого черты типа, чтобы предотвратить ссылки на lvalue? https://stackoverflow.com/a/7863645/620304
Благодарю.
Итак, вопрос. Имеет ли смысл отмечать ссылку
как const при передаче в качестве параметра?
Вот одно место, где это делается в стандарте C ++ 11:
template <class T> reference_wrapper<T> ref(T&) noexcept;
template <class T> reference_wrapper<const T> cref(const T&) noexcept;
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
То есть const T&&
используется для захвата всех значений r, постоянных или нет, и их сброса во время компиляции, при этом допускается использование даже значений lvalue const
Значения связывать и работать.
Теперь это также может быть сделано с T&&
и enable_if
ограничение. Но если есть что-то, чему C ++ научил нас за последние несколько десятилетий: не сжигайте мосты в языковом дизайне. Программист C ++ часто находит умный способ использовать языковую функцию, которая изначально считалась бесполезной. И именно в этом духе const T&&
был оставлен в качестве легального варианта.
Других решений пока нет …