Hi and welcome to stack overflow.
As this little test program shows, no matter how you specify the type of k, the compiler will never let you lose the constness of i.
#include <iostream> #include <type_traits> #include <string> #define XSTR(s) STR(s) #define STR(s) #s template<class T> struct type; template<> struct type<int> { static std::string name() { return "int"; } }; template<class T> struct type<T&&> { static std::string name() { return type<T>::name() + " &&"; } }; template<class T> struct type<T&> { static std::string name() { return type<T>::name() + " &"; } }; template<class T> struct type<T const> { static std::string name() { return type<T>::name() + " const"; } }; #define REPORT_CONST(decl, var, assign) \ { \ decl var = assign; \ do_it(STR(decl var = assign;), var); \ } template<class Var> void do_it(const char* message, Var&&) { std::cout << "case: " << message << " results in type: " << type<Var>::name() << '\n'; } int main() { const int i = 42; REPORT_CONST(const auto &, k, i); REPORT_CONST(auto &, k, i); REPORT_CONST(auto &&, k, std::move(i)); REPORT_CONST(auto const &&, k, std::move(i)); REPORT_CONST(int const&, k, i); // REPORT_CONST(int &, k, i); // error: binding reference of type 'int&' to 'const int' discards qualifiers }
Expected results:
case: const auto & k = i; results in type: int const & case: auto & k = i; results in type: int const & case: auto && k = std::move(i); results in type: int const & case: auto const && k = std::move(i); results in type: int const & case: int const& k = i; results in type: int const &
http://coliru.stacked-crooked.com/a/7c72c8ebcf42c351
Note also the decay of named r-values to l-values.
ks).