I switched the Template Factory functions to use (and understand) std :: forward to support rvalues ββand move semantics. My regular Factory template functions for template classes always marked parameters as 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; }
Compiles as expected. I originally converted MakeMyPair to pass parameters as const, but this will not compile on my Mac using 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: posix template<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; }
There is no suitable function for calling the MakeMyPair_Forward candidate function [with T = int, U = bool] is not viable: unknown conversion from 'int' to 'const int &' for the 1st argument
This makes sense from http://en.cppreference.com/w/cpp/utility/forward , which outputs const, and I pass the lvalue.
- If the wrapper () call passes rvalue std :: string, then T is output to std :: string (not std :: string &, const std :: string &, or std :: string &), and std :: forward guarantees that the rvalue link is passed to foo.
- If the wrapper () call passes const lvalue std :: string, then T is output to const std :: string &, and std :: forward ensures that the const lvalue reference is passed to foo.
- If the wrapper () call does not pass const const lvalue std :: string, then T is output to std :: string &, and std :: forward ensures that it is not const The lvalue reference is passed to foo.
Removing const works the way I want with rvalues ββand lvalues. Only passing rvalues ββas types will work with const parameters on MakeMyPair_Forward parameters.
//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)); }
So the question is. Does it make sense to mark the rvalue reference as const when passed as a parameter? This is not how I can change rvalue, it is just temporary. I was a little surprised that it was compiled with const after I worked and corrected my code. Why do you mark the rvalue parameter as const? Would it make sense to provide an API that accepts rvalues? If so, could you use type traits instead to prevent references to lvalue? stack overflow
Thanks.