为什么是
int x;
if (cin >> x){}
相当于
cin >> x;
if (cin){}
从这段代码看来,我觉得我们正在使用 cin 作为变量。但是,我认为它是一个函数。当 x 拥有我们从键盘输入的任何值时,为什么我们可以以这种方式使用 cin?
为什么是
int x;
if (cin >> x){}
相当于
cin >> x;
if (cin){}
从这段代码看来,我觉得我们正在使用 cin 作为变量。但是,我认为它是一个函数。当 x 拥有我们从键盘输入的任何值时,为什么我们可以以这种方式使用 cin?
cin
是一个istream
类的对象,代表标准输入流。它对应于cstdio
流中的stdin
。流运算符>>
重载返回对同一流的引用。流本身可以通过转换运算符在布尔条件下评估为true或false。
cin
提供格式化流提取功能。操作cin >> x;
其中"x"是int类型,如果输入非数字值,则会失败。
if(cin>>x)
false
。这个关于使用C++ I/O的技巧和窍门的网站也会对您有所帮助。operator void*
转换成员的原因是,直到C++11才将已经存在的explicit
关键字扩展到适用于转换运算符以及构造函数。一个非显式的operator bool()
会给程序员带来太多的机会去踩坑。虽然operator void*()
也存在问题,但"safe bool idiom"(安全布尔型惯用法)可以解决这个问题,但仅仅扩展explicit
关键字就可以达到和"safe bool idiom"一样的效果,并且不需要使用大量的SFINAE技巧。operator bool
,而是使用 operator void*
。operator bool
可以使它在算术上下文中使用,而 operator void*
防止这种情况发生,因为 void
是不完全的类型。在 MSVC 编译器的实现中,如果没有设置失败标志(这不能为 0,因此在布尔上下文中被评估为 true
),则 operator void*
返回对象的地址,否则返回 0(在布尔上下文中为 false)。 - lccarrasco,而在C++11中使用
operator bool()`。 - Evgeni Sergeev--std=c++98
),则std::cout<<(std::cin>>x)
将无法通过编译。在所有版本的标准中,从std::cin>>x
返回的值是对std::cin
对象的引用,并且没有重载std::basic_ostream operator>> (const std::basic_istream&)
。在C++11之前,编译器会使用std::basic_istream::operator void*()
。如果输入失败,则返回空指针,如果输入成功,则返回非空指针。这就是为什么你会看到0
或0x48650
的原因。(续) - David Hammenvoid*
转换运算符在 C++11 中已被删除,用 explicit operator bool()
替代。explicit
标签(C++11 新增)明确告诉编译器不要在 std::cout<<(std::cin>>x)
中使用该转换。这个表达式在遵循 C++11、C++14、C++17 或 C++20 标准版本的编译器中应产生编译错误。 - David Hammenbool
。例如,假设foo
是一个指针类型,我更喜欢看到if ((foo != nullptr) && foo->is_valid())
而不是if (foo && foo->is_valid())
。但这只是个人偏好。在有一半像样的编译器的情况下,这两个语句在生成的汇编代码方面是相同的。 - David Hammencin
是istream
类型的全局变量,而不是函数。
istream
类重载了>>
运算符进行输入,并返回调用该运算符的对象(cin
)的引用。
>>
重载时才可以。 - SLakscin
是std
命名空间中的变量。
operator>>
返回对cin
的引用,因此您可以写:cin >> a >> b
,而不是cin >> a; cin >> b;
std::cin
是 istream
类的一个对象,表示标准输入流(即键盘),对应于 C 语言中的 stdin
。
cin >> x
首先会从标准输入流读取一个整数,并将其赋值给 x
,然后返回一个指向 cin
的自引用。因此,函数调用 cin >> x
的返回值仍然是 cin
。if(cin)
和 if(cin >> x)
相似。标准 IO 库 为流定义了一个类似于以下实现的函数:explicit operator bool() const; // C++11
或者
operator void*() const; //C++98, C++2003
cin >> x
评估为
cin
std::cin
是 std::istream
类的一个实例。
cin >> x
只是在 cin
对象上调用一个函数。您可以直接调用该函数:
cin.operator >>(x);
operator >>
函数返回调用它的流的引用。您可以调用以下代码:cin >> x >> y;
cin.operator >>(x).operator >>(y);
或者:
std::istream& stream = cin.operator >>(x);
stream.operator >>(y);
这个难题的最后一部分是std::istream
可以转换为bool
。 bool相当于调用!fail()
。
因此,在以下代码中:
int x;
std::istream& stream = std::cin.operator >>(x);
bool readOK = !stream.fail();
if (readOK)
{
std::cout << x << "\n";
}
bool readOK = !stream.fail();
可以简化为 bool readOK = stream;
。
您不需要一个单独的 bool
来存储流的状态,所以可以直接使用 if (stream)
。
删除临时的 stream
变量后得到 if (std::cin.operator >>(x))
。
直接使用运算符回到原始代码:
int x;
if (std::cin >> x)
{
std::cout << x << "\n";
}
std::cout<<(std::cin>>x);
失败,则输出 0
,如果成功,则输出 0x486650
,为什么它不会输出 1
。 - Abhishek Manestd::cout<<(std::cin>>x);
无法编译。 - Alan Birtles1) cin
是istream
的一个实例,参见http://www.cplusplus.com/reference/iostream/cin/。
2) istream
的>>
运算符将返回其左操作数,这里是cin
,参见http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/。如果没有从cin
中提取出任何字符,则该运算符将设置failbit
。如果读者已完成EOF
,则不会再有字符可读,此时也会设置failbit
。
3) 在上述第2点中,当读取操作后条件被评估时,if (cin >> x)
应该像 if (cin)
一样,参考此链接 http://www.cplusplus.com/reference/ios/ios/operator_bool/,你会看到,这个 if
块将返回:
如果至少设置了 failbit
或 badbit
中的一个,则返回空指针。否则返回其他某些值(适用于 C++98 标准)。
如果至少设置了这些错误标志之一,则函数返回 false,否则返回 true(适用于 C++11 标准)。
cin
和cout
视为“魔法”。当然,它们并不是魔法,但它们是使用许多相当先进的技术构建的。现在最好继续前进,等你掌握了类、继承和运算符重载后再回来看它们。 - Anders Abelif
语句所接受的表达式只能是布尔类型、整数类型或指针类型。类std::istream
提供了将输入流转换为布尔类型的功能,正是这个转换运算符用于判断执行if
分支还是else
分支。 - David Hammen