文章目录
- 例一:`Foo(m);` 是定义名为 `m` 的对象
- 例二:`Foo(m).i;` 传入实参 `m`
- 例三:`func(Foo(m));` 传入实参 `m`
- 例四:`S(cout)(1)` 定义名为 `cout` 的对象
- 例五:`S(std::cout)(1)` 传入实参 `std::cout`
你知道吗,如果
Foo 是一个类,那么执行含有
Foo(m) 的语句时,可能并不会把
m 作为实参传给
Foo 的构造函数!还有一种可能是调用默认构造函数,去定义一个
Foo 的对象
m!
那这两种情况分别在什么时候发生呢?我们知道,C++中圆括号 () 有时候是多余的存在,比如 int i = (1+3);,把括号去了 int i = 1+3;,两条语句是等价的。对于含 Foo(m) 的语句,这对括号也可能是多余的。C++处理这种语句的原则是能简单就简单,如果能省略括号(无语法错误)那就省略!当然了,省略完括号得加上一个空格,变成 Foo m。下面举五个例子。首先我们定义一个 Foo 类。
struct Foo
{
int i;
Foo(int i0) : i(i0) {}
};
例一:Foo(m); 是定义名为 m 的对象
对于 Foo(m); 括号省略后,语句变成 Foo m;。语法没有任何问题,所以编译器决定把括号省略。
int main()
{
Foo(m);
return 0;
}

但是上述代码会在编译时产生错误,因为 Foo 没有默认构造函数啊,所以 Foo m; 当然是会报错的。
例二:Foo(m).i; 传入实参 m
对于Foo(m).i;,我们把括号去掉,语句变成 Foo m.i;,显然语法错误。编译时会报 m 未定义的错误。
这就说明括号是不能去的,即 m 会作为实参传给 Foo 的构造函数,创建一个匿名对象,然后访问其名为 i 的数据成员。
// main函数中
int m = 10;
cout << "Output:\t" << Foo(m).i << '\n';
Output: 10
例三:func(Foo(m)); 传入实参 m
func 是一个函数,有一个 Foo 类型的形参。我们把括号去掉,语句变成 func(Foo m); ,显然是非法的,因为实参里面不能有类型名。故括号不能去,即 m 应作为参数传给 Foo 的构造函数。
int func(Foo foo) { return foo.i; }
int main()
{
int m = 10;
cout << "Output:\t" << func(Foo(m)) << '\n';
return 0;
}
Output: 10
为了说明下面两个例子,我们定义一个新的类 S。S 重载了调用运算符 (),因此其对象是一个函数对象。
#include <iostream>
using std::cout;
using std::cerr;
struct S
{
ostream &os;
S(ostream &o = cerr) : os(o) {}
void operator()(int x)
{
os << "x = " << x << '\n';
}
};
例四:S(cout)(1) 定义名为 cout 的对象
cout
我们先来试试看 S()(1); 会有什么结果。它调用默认构造函数,创建一个可调用的函数对象,os 初始化为 cerr。这个对象接受一个实参 1 然后被调用,由 cerr 输出 x = 1。
如果我不想默认初始化,便传入 cout 给 S 的构造函数作为实参。此时语句变为 S(cout)(1)。这能不能达到预期效果呢?我们试着把括号去掉,变成 S cout(1),这看着确实是语法正确的,意思是通过传入实参 1 ,来定义一个名为 cout 的 S 对象。既然语法合法,则括号可去。
// main函数
S(cout)(1);

但编译显然是会报错的,为什么呢,因为 S 并没有接受一个 int 对象的构造函数。
这倒还算好的,因为报错了,我们能通过错误检查出我们代码的问题。如果 S 果真有接受一个 int 对象的构造函数,便不会报错,但达不到我们的预期效果,代码问题的排查也就更困难了。
那如果要达到预期效果,正确的做法是什么呢?请看例五。
例五:S(std::cout)(1) 传入实参 std::cout
加上了全局作用域,这括号可就去不得了:S std::cout(1) 显然非法,std::cout 不能作为我们自定义对象的名字。因此 std::cout 会如预期一样作为实参传入 S 的构造函数。
S(std::cout)(1);
x = 1
这就是为什么很多人建议用 std::cout 而非 cout 的原因,就是怕上述的情况。using std::cout; 倒还好了,只要我们不主动定义 名字叫 cout 的对象一般不会出错,除非是上述这种编译器去括号来定义的这种意想不到的错误。相较而言,using namespace std; 是风险最高的,你不知道啥时候,自己自定义的一个对象名字就把标准库的给隐藏了。
但是图省事,对于使用次数较多的名字,我还是会用 using std::cout;;对于只用一两次的名字,我就不用 using 声明了吧,而是加上 std::。另外自己要清楚 Foo(m) 的这些情况,如此写出与预期效果相符的代码也就容易多了。












![[QMT]08-从本地行情数据解析历史K线信息](https://img-blog.csdnimg.cn/img_convert/d0b88aeecb825ce13e0c96487e05008b.png)






