My question would have a boolean answer: yes or not. Whichever it would be, can someone explain how the following code is compiled by both GNU-g++ 4.9.2 and clang 3.5, while GNU-g++ 5.1.1 no longer accepts it, claiming that there is no matching operator==?
And how it could be changed, for this last compiler, in order to have the same results i.e. to have the operator>> able to distinguish, in such a simple way, whether
it is called by the standard input stream or by something else?
# include <iostream>
# include <fstream>
struct S {};
std::istream& operator >> (std::istream& i, S& s)
{
if(i == std::cin) std::clog << "this is standard input\n";
else std::clog << "this is some other input stream\n";
return i;
}
int main(int narg, const char ** args)
{
S s;
std :: cin >> s;
std::ifstream inp(args[1]);
inp >> s;
}
// to be executed with the name of an existing
// disk file on the command line....
No. There's no operator== that operates on std::istream objects.
Your being able to compare two std::istreams is an unfortunate consequence caused by the conversion function of std::istream, specifically operator void*. In the expression i == std::cin, both i and std::cin are implicitly converted to void*, and the resulting values are compared. This is not really meaningful. This conversion function was removed in C++11 (replaced by an explicit conversion function, which won't be called in this situation), so if you enable the C++11 mode, the code will not compile.
As is stated here, if you want to check whether the reference i refers to std::cin, you can use &i == &std::cin.
Standard C++ streams don't have ==, >, < operators because they are not very meaningful in that context: what should "stream a is > than stream b" mean?
However, it shouldn't matter what type of istream you're dealing with: as long as you're not using specific methods defined in descendant classes (like is_open), base methods are shared (extracting, for instance). Whether you're extracting a string from a istringstream or a ifstream, you just do in >> str and let polymorphism take action.
If you really want to know the polymorphic type of the istream, you can use typeid or, simply, function overloading. In your case, with RTTI(typeid)
if ( typeid(in) == typeid(std::cin) )
// cin
else
// another istream type
Using overloading:
std::istream& operator >> (std::istream& i, S& s)
{
std::clog << "this is standard input\n";
return i;
}
std::ifstream& operator>>(std::ifstream& i, S& s)
{
std::clog << "this is some file input stream\n";
return i;
}
Related
I am a C++ beginner,
#include <iostream>
int main()
{
char v1;
// valid no warning
std::cout << (std::cin >> v1) << std::endl; // return value of the expression expected
return 0;
}
// output: 1
// return value of the expression is 1?
Is the return value of (std::cin >> v1) really 1? Why?
I don't know of a current compiler that will accept your code as it stands right now. g++, clang and Microsoft all reject it, saying they can't find an overload to match the arguments (i.e., an operator<< for ostream that takes an istream as an operand).
It's possible to get the result you've posited with code on this order: std::cout << !!(std::cin >> v1) << "\n";. Depending on the age of the compiler and standard with which it complies, this does one of two things.
With a reasonably current compiler, this will use the Boolean conversion on the istream to get it to match the ! operator, then apply that (twice) to the result, so you write out the result of that operator.
With old enough compilers, there won't be a Boolean conversion operator, but there will be an overload of operator!, which also does a conversion to Boolean (but negated in sense, of course). The result of that will then be negated by the second !.
Either way, you end up writing out a Boolean value (or int containing zero or one on an old enough compiler) that indicates whether the stream is in a failed or successful state.
This is done to allow you to check input as you're reading it, so you can process input data sanely. For example, when/if you want to read all the values in a file, stopping at the end of the file, or when you encounter something that can't be interpreted as the desired type, you can write code on this general order:
// read integers from a file and print out their sum
int temp;
int total = 0;
while (std::cin >> temp) {
total += temp;
}
std::cout << total << "\n";
The while loop uses the conversion to Boolean to determine whether an attempt at reading a value was successful or not, so it continues reading values as long as that happens successfully, and quits immediately when reading is unsuccessful.
One common source of errors is to write a loop on this order instead:
while (std::cin.good()) { // or almost equivalently, check for end of file.
std::cin >> temp;
total += temp;
}
But loops like this get the sequence incorrect. One common symptom of the problem with this is that the last number in the file will be added to the total twice instead of once.
std::cin >> v1 returns cin; Not sure what type it gets converted to for std::cout, but most likely it indicates the state of cin, where 1 is good
Is the return value of (std::cin >> v1) really 1
No, see the ref for cin, it will return a istream.
Your codes will not work, we can not pass ::istream (std::cin) to operator<< of a std::ostream (std::cout).
Shoule be like the following:
char v1;
cout << "Input a char:";
cin >> v1;
The program only works for Pre-C++11 because the conversion to bool is not explicit.
Starting from C++11, the program will no longer work because the conversion to bool is explicit.
Note that std::cin >> v1; returns std::cin and not 1. But there is no operator<< for std::ostream that takes a std::cin.
The reason it works for Pre-C++11 is because in this case the conversion to bool was not explicit. But starting from C++11, the conversion to bool was made explicit and so the code no longer compiles.
For example,
bool b = std::cin; //WORKS for Pre-C++11 but FAILS for C++11 & onwards
bool b{std::cin}; //OK, WORKS for all versions(Pre-C++11 as well as C++11 & onwards) because in direct initialization we can use explicit conversion
Im working with the book SFML Game Development by Examples and I dont really get what this sentence does. I've never seen something like this
void Anim_Directional::ReadIn(std::stringstream& l_stream){
l_stream >> m_frameStart >> m_frameEnd >> m_frameRow
>> m_frameTime >> m_frameActionStart >> m_frameActionEnd;
}
In C++ they got the "bright" idea of overloading the rightshift and leftshift operators with streams to represent serialization/deserialization.
stream >> var
means "read var from stream".
Symmetrically
stream << var
mean "put var into stream"
The operation of "streaming" in or out also returns the stream, so you can chain operations like:
stream >> var1 >> var2;
Note that the "streaming" was chosen just because of the look and because the priority was considered reasonable, but it's still just an overloaded operator and implies for example no strict sequence of evaluation. For example in:
stream << f() << g();
may be function g is called (somewhat surprisingly) before function f.
NOTE: the sequencing problem was handled by hammering this special case in last C++ standard (C++17). While it doesn't hold in general it's guaranteed for shift operators (presumably for this specific reason). So in f()+g() may be f is called later than g, but in f()<<g() this cannot happen.
C++ allows you to overload >> and << operators. std::stringstream is a derivative of std::istream and it inherits the >> operator overloads of std::istream.
The std::istream has a bunch of overloads for many common types. You can find a list of them here.
A typical std::istream >> operator overload looks as follows:
std::istream& operator>>(std::istream& stream, YourType& var) {
/*
** code here to parse and read a 'YourType' into 'var'
*/
/* var is set */
return stream; /* return the same stream to allow chaining */
}
When you do some_stream >> YourType_object, the matching >> operator overload is invoked. In the aforementioned case, our operator overload is invoked with stream parameter taking some_stream and var taking YourType_object.
The >> overloads (and << overloads too) intelligently return the stream which they operated; thereby, allowing a series of >> operators to be chained.
I've used statements such as this quite a bit in my C++ programming:
std::string s;
std::ifstream in("my_input.txt");
if(!in) {
std::cerr << "File not opened" << std::endl;
exit(1);
}
while(in >> s) {
// Do something with s
}
What I want to know is, why does this work?
I looked at the return value of operator>>, and it's an istream object, not a boolean. How does an istream object somehow get interpreted as a bool value that can be put inside of if statements and while loops?
The base class std::basic_ios provides an operator bool() method that returns a boolean representing the validity of the stream. For example, if a read reached the end of file without grabbing any characters, then std::ios_base::failbit will be set in the stream. Then operator bool() will be invoked, returning !fail(), at which time extraction will stop because the condition is false.
A conditional expression represents an explicit boolean conversion, so this:
while (in >> s)
is equivalent to this
while (static_cast<bool>(in >> s))
which is equivalent to this
while ((in >> s).operator bool())
which is equivalent to
while (!(in >> s).fail())
std::basic_ios, from which the input and output streams inherit, has the conversion function operator bool (or operator void* prior to C++11 to get around the safe-bool problem, which is no longer an issue thanks to the explicit keyword).
See std::basic_ios::operator bool:
This operator makes it possible to use streams and functions that return references to streams as loop conditions, resulting in the idiomatic C++ input loops such as while(stream >> value) {...} or while(getline(stream, string)){...}. Such loops execute the loop's body only if the input operation succeeded.
Suppose I wanted operator>> to extract entire lines from an istream instead of whitespace-separated words. I was surprised to see that this, although horrible, actually worked:
#include <iostream>
#include <string>
namespace std {
istream &operator>>(istream &is, string &str) {
getline(is, str);
}
}
int main() {
std::string line;
std::cin >> line;
std::cout << "Read: '" << line << "'\n";
}
If I type multiple words into stdin, it actually does call my operator and read an entire line.
I would expect this definition of operator>> to conflict with the official one, producing a link error. Why doesn't it?
Edit: I thought maybe the real operator>> was a template, and non-template functions take precedence, but this still works just as well:
namespace std {
template<typename charT>
basic_istream<charT> &operator>>(basic_istream<charT> &is, basic_string<charT> &s) {
getline(is, s);
}
}
It happens to work because the official template is less specific (there are additional template arguments).
However it is Undefined Behaviourâ„¢. You are only permitted to provide overloads of standard library symbols for your own types. If you come across another standard library that will define extra overloads (it may), it will stop working and you won't know why.
I have a class template, which is -- among other things -- supposed to overload istream so it accepts the user's input and adds (pushes) it into a vector, which holds type T elements.
friend istream &operator>> (istream &in, Set<T> &s)
{
int ctr = 0;
string tmp;
T val;
while (true) {
cout << "\tElement #" << ctr + 1 << ": ";
getline (in, tmp);
if (tmp == "\0") break;
// MISSING CODE HERE: "Convert" tmp into val
s.add(val);
ctr = s.size();
}
return in;
}
This works fine with Set<string>, but I need to find a way to make it function with any primitive data type, too, i.e. Set<integer>, for example.
I tried doing
stringstream(tmp) >> val
but that then doesn't work with Set<string>.
I guess the input needs to be read in as string; how, then, do I cast the input string into T type to pass it to the .add() function?
You could use a stringstream object (created from tmp) to extract the correct value if it is not a string. Note you will have to overwrite operator>> for ostream if you need more than just the built-in types (e.g. int)
Alternatively, you can define overloads of a convert() function for each T you encounter to provide proper conversion from the string tmp to the required type. The proper overload (if exists) will be selected based on your template parameter.
You can use boost::lexical_cast to convert strings to other types lexicographically.
template<class T>
friend istream &operator>> (istream &in, Set<T> &s) {
int ctr = 0;
string tmp;
T val;
while (true) {
cout << "\tElement #" << ctr + 1 << ": ";
getline (in, tmp);
if (tmp == "\0") break;
val = boost::lexical_cast<T>(tmp);
s.add(val);
ctr = s.size();
}
return in;
}
Alternatively, you can use std::istringstream.
std::istringstream sstream(tmp);
sstream >> val;
Note that boost::lexical_cast throws an exception if the cast wasn't successful, and std::istringstream does not (you need to check this manually).
There a few issues in the code that you may like to address:
getline (in, tmp);
That need to check the return value:
if(!getline (in, tmp))
// handle end-of-file or read failure
// read okay, tmp contains the read line
Next:
if (tmp == "\0") break;
It's not very common to have embedded zeros in text files. May be this piece is trying to detect the end-of-file condition, which should be handled by checking the return value of getline or if(in) statement.
stringstream(tmp) >> val;
That creates a temporary string stream and tries to invoke operator>> on it. Well, there are two kinds of operator>> for std::istream:
std::istream member functions that accept temporary (r-values) and l-values std::istream object
free standing ones that take std::istream by reference to non-const, which don't accept r-values. (In C++11 it can accept it also as std::istream&& allowing for r-values).
Hence, the above statement can only stream into built-in types for which there is a member operator>> in std::istream.
So, that statement can be replaced with:
std::istringstream ss(tmp);
ss >> val;
That would need to have error handling again to check whether entire str was parsed into val, so, as others have said here, it's easier to use boost::lexical_cast<> that does error checking for you:
val = boost::lexical_cast<T>(tmp);
If you don't insist on reading the full line, rather reading white-space separated tokens, then the loop can look like this:
template<class T>
friend std::istream &operator>>(std::istream &in, Set<T> &s) {
int ctr;
T val;
while(in >> val) {
ctr = s.size();
std::cout << "\tElement #" << ctr + 1 << ": ";
s.add(val);
}
// end-of-file or parsing failure
if(!in.eof()) {
// handle failuer to parse or read error
}
}