I wrote a move
to imitate std::move
, and try to use a new struct Foo
to test it. However, something wrong happened.
.\main.cpp: In function 'int main()':
.\main.cpp:46:7: error: conflicting declaration 'Foo x'
46 | Foo(x);
| ^
.\main.cpp:43:15: note: previous declaration as 'std::string x'
43 | std::string x = "123";
| ^
I replace the code Foo(x)
with Foo foo = Foo(x)
, then everything went just fine.
I'm using MinGW32 g++ 9.2.0
, compiling with command g++ main.cpp -std=c++14
See the code below for more detail:
#include <iostream>
template <class T>
struct Remove_Reference {
typedef T type;
};
template <class T>
struct Remove_Reference<T&> {
typedef T type;
};
template <class T>
struct Remove_Reference<T&&> {
typedef T type;
};
template <typename T>
constexpr typename Remove_Reference<T>::type&& move(T&& x) noexcept {
return static_cast<typename Remove_Reference<T>::type&&>(x);
}
struct Foo {
Foo() {}
Foo(std::string&& foo) : val(foo) {
std::cout << "rvalue reference initialize" << std::endl;
}
Foo(const std::string& foo) : val(::move(foo)) {
std::cout << "const lvalue reference initialize" << std::endl;
}
std::string val;
};
void call(std::string&& x) {
std::cout << "rvalue reference: " << x << std::endl;
}
void call(const std::string& x) {
std::cout << "const lvalue reference: " << x << std::endl;
}
int main() {
std::string x = "123";
Foo{x};
// Foo(x);
Foo{::move(x)};
Foo(::move(x));
call(x);
call(::move(x));
return 0;
}
This statement:
Foo(x);
is not a function call, or a constructor call. It's just a declaration, that says x
is of type Foo
. The parentheses are optional around the declarator x
, so it's equivalent to:
Foo x;
This of course gives an error, since you already have a std::string
named x
, and you can't give the same name to multiple entities in the same scope.
Note that the expression:
Foo(x)
is different than the statement above (with the ;
). This expression can mean different things depending on the context it is used in.
For example, this code:
Foo foo = Foo(x);
is perfectly fine. This does copy initialization of a variable named foo
, from the expression Foo(x)
, which is a temporary Foo
constructed from the argument x
. (It's not particularly important here, but from c++17, there's no temporary on the right hand side; the object just gets constructed in place).