It seems that a constructor that takes a non-const reference to an istream cannot be constructed with a temporary value in C++.
#include <iostream>
#include <sstream>
using namespace std;
class Bar
{
public:
explicit Bar(std::istream& is) {}
};
int main()
{
istringstream stream1("bar1");
Bar bar1(stream1); // OK on all platforms
// compile error on linux, Mac gcc; OK on Windows MSVC
Bar bar2(istringstream("bar2"));
return 0;
}
This comp开发者_如何学JAVAiles fine with MSVC, but not with gcc. Using gcc I get a compile error:
g++ test.cpp -o test
test.cpp: In function ‘int main()’:
test.cpp:18: error: no matching function for call to ‘Bar::Bar(std::istringstream)’
test.cpp:9: note: candidates are: Bar::Bar(std::istream&)
test.cpp:7: note: Bar::Bar(const Bar&)
Is there something philosophically wrong with the second way (bar2) of constructing a Bar object? It looks nicer to me, and does not require that stream1 variable that is only needed for a moment.
EDIT: In response to Johannes Schaub's comment I'd like to give a bit more context. First, this is not the first time I have been annoyed by this behavior of C++, so I am genuinely interested in the higher level philosophical discussion of this issue. That said, in this particular case I have a class that reads in a file that contains data used to construct the object. I also like to write automated tests that use a string instead of the file. But using the file for construction is the primary use case. So I decided to make a constructor that takes an istream, so I could use either a file(stream), or a string(stream). That is how I got here. My test programs construct objects directly from strings, to simulate reading files. This saves me the trouble of creating separate data files for each little test.
This is just how C++ works currently: you cannot bind non-const references to temporary objects. MSVC is non-standard in allowing this.
C++0x will have r-value references and change things around a bit here. There are various philosophical interpretations people have tried to apply—for both sides of the issue—but I haven't found one that is wholly convincing. It seems more of "you just have to pick one behavior and stick to it", which explains both current C++ and 0x's changes: the chosen behavior has shifted.
Roger is right… this is a generic policy of C++ that only const references may bind to temporaries. I don't think rvalue references would help you, though, because in the case of passing a non-temporary stream you do want to continue using its modified state.
More to the point, why not replace the constructor with a friend
extractor istream &operator>>(istream &s, Bar &b)
? At the cost of adding an uninitialized state to the object, the syntax would be even more C++-ish.
精彩评论