为什么不能将圆括号正确地视为构造函数调用?
Why can't round bracket be correctly regarded as a constructor calling?
我写了一个move
来模仿std::move
,尝试用一个新的struct Foo
来测试一下。然而,出了点问题。
.\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";
| ^
我将代码Foo(x)
替换为Foo foo = Foo(x)
,然后一切正常。
我正在使用 MinGW32 g++ 9.2.0
,使用命令 g++ main.cpp -std=c++14
进行编译
查看下面的代码了解更多详情:
#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;
}
这条语句:
Foo(x);
不是函数调用,也不是构造函数调用。这只是一个声明,说 x
是 Foo
类型。括号在声明符 x
两边是可选的,所以它等价于:
Foo x;
这当然会出错,因为您已经有一个名为 x
的 std::string
,并且您不能为同一范围内的多个实体指定相同的名称。
注意表达式:
Foo(x)
不同于上面的 语句 (带有 ;
)。根据使用的上下文,此表达式可能有不同的含义。
例如,这段代码:
Foo foo = Foo(x);
完全没问题。这会从表达式 Foo(x)
复制名为 foo
的变量的初始化,表达式 Foo(x)
是根据参数 x
构造的临时 Foo
。 (这里不是特别重要,但从 c++17 开始,右侧没有临时对象;对象只是就地构建)。
我写了一个move
来模仿std::move
,尝试用一个新的struct Foo
来测试一下。然而,出了点问题。
.\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";
| ^
我将代码Foo(x)
替换为Foo foo = Foo(x)
,然后一切正常。
我正在使用 MinGW32 g++ 9.2.0
,使用命令 g++ main.cpp -std=c++14
查看下面的代码了解更多详情:
#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;
}
这条语句:
Foo(x);
不是函数调用,也不是构造函数调用。这只是一个声明,说 x
是 Foo
类型。括号在声明符 x
两边是可选的,所以它等价于:
Foo x;
这当然会出错,因为您已经有一个名为 x
的 std::string
,并且您不能为同一范围内的多个实体指定相同的名称。
注意表达式:
Foo(x)
不同于上面的 语句 (带有 ;
)。根据使用的上下文,此表达式可能有不同的含义。
例如,这段代码:
Foo foo = Foo(x);
完全没问题。这会从表达式 Foo(x)
复制名为 foo
的变量的初始化,表达式 Foo(x)
是根据参数 x
构造的临时 Foo
。 (这里不是特别重要,但从 c++17 开始,右侧没有临时对象;对象只是就地构建)。