I did some further experimentation on the topic of my previous question and have another one.
Consider the code below where, as I expeded, both l_ref
are r_ref
are const
:
#include <string>
#include <iostream>
struct Func
{
void operator()() const
{
static_assert(!std::is_const_v<decltype(v)>);
static_assert(std::is_same_v<decltype(v), std::string>);
static_assert(std::is_same_v<decltype(this), const Func*>);
auto& l_ref = v;
static_assert(std::is_same_v<decltype(l_ref), const std::string&>);
//my idea was that it does not move because it is const r-value reference
auto&& r_ref = std::move(v);
static_assert(std::is_same_v<decltype(r_ref), const std::string&&>);
std::cout << "v: " << v;
}
std::string v;
};
Now consider the following lambda were wired things start to happen and l_ref
and r_ref
are not const:
int main()
{
std::string v = "abc";
auto func = [v]()
{
static_assert(!std::is_const_v<decltype(v)>);
static_assert(std::is_same_v<decltype(v), std::string>);
auto& l_ref = v;
static_assert(std::is_same_v<decltype(l_ref), std::string&>);
auto&& r_ref = std::move(v);
static_assert(std::is_same_v<decltype(r_ref), std::string&&>);
//what happens here?
auto a = std::move(v);
static_assert(std::is_same_v<decltype(a), std::string>);
std::cout << "v: " << v;
};
func();
return 0;
}
v
should not move at line auto a = std::move(v);
because lambda is not mutable
so it is something similar to void operator() const
of the struct Func
, but at the same time v
is not const
and std::move(v)
is non-const r-value reference, so what mechanism prevents move constructor of std::string
from being called?
CodePudding user response:
The move and copy constructors are both part of the same overload set. The compiler will either choose the copy or the move constructor according to the value category and const-ness of the arguments.
You second example is wrong and won't compile according to the standard. decltype(l_ref)
and decltype(r_ref)
are indeed const. See this live example.
MSVC seem to accept the code, but this is a compiler bug. You should report such problem to the microsoft msvc developpers.
To prove visual studio is wong and that the variable is indeed const, look at the assembly generated (unmangled):
call std::basic_string<char,std::char_traits<char>,std::allocator<char> >::basic_string<char,std::char_traits<char>,std::allocator<char> >(std::basic_string<char,std::char_traits<char>,std::allocator<char> > const &)
As you can see, it calls the copy constructor, not the move constructor according to the function parameter:
std::basic_string<char,std::char_traits<char>,std::allocator<char> > const &