When I try to use a ternary conditional operator (?:) with stream buffer redirection, gcc produces 'synthesized method first required here' error. What is the problem, and how to correct the following program?
#include <fstream>
#include <iostream>
int main(int argc, char* argv[])
{
using namespace std;
cout << cin.rdbuf(); //OK
ofstream("tmp.txt") << cin.rdbuf(); //OK
int i=1;
(i > 1 ? ofstream("tmp.txt") : cout) << cin.rdbuf(); //Compilation ERROR. Why?
return 0;
}
compiled with gcc4.4:
...
/usr/include/c++/4.4/bits/ios_base.h: In copy constructor ‘std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)’:
/usr/include/c++/4.4/bits/ios_base.h:790: error: ‘std::ios_base::ios_base(const std::ios_base&)’ is private
/usr/include/c++/4.4/iosfwd:47: error: within this context
/usr/include/c++/4.4/iosfwd: In copy constructor ‘std::basic_ostream<char, std::char_traits<char> >::basic_ostream(const std::basic_ostream<char, std::char_traits<char> >&)’:
/usr/include/c++/4.4/iosfwd:56: note: **synthesized method** ‘std::basic_ios<char, std::char_traits<char> >::basic_ios(const std::basic_ios<char, std::char_traits<char> >&)开发者_如何转开发’ **first required here**
../item1_1.cpp: In function ‘int main(int, char**)’:
../item1_1.cpp:12: note: synthesized method ‘std::basic_ostream<char, std::char_traits<char> >::basic_ostream(const std::basic_ostream<char, std::char_traits<char> >&)’ first required here
This compiled OK with my version of clang, I think that it may be a gcc bug.
From my reading of the standard, cout
is an lvalue of type std::ostream
and ofstream("tmp.txt")
is an rvalue of type std::ofstream
.
Neither has any cv-qualifiers and std::ostream
is a base class of std::ofstream
so the conditional operator is valid an the result is an rvalue and has type std::ostream
.
There is no copying of either operand implied.
if
E1
andE2
have class type, and the underlying class types are the same or one is a base class of the other:E1
can be converted to matchE2
if the class ofT2
is the same type as, or a base class of, the class ofT1
, and the cv-qualification ofT2
is the same cv-qualification as, or a greater cv-qualification than, the cv-qualification ofT1
. If the conversion is applied,E1
is changed to an rvalue of typeT2
that still refers to the original source class object (or the appropriate subobject thereof). [Note: that is, no copy is made. ]
The operator<<
overload that you are using is a member of std::ostream
so there is no need to bind a temporary to a non-const reference, the member can be called on a non-const rvalue.
basic_ostream<charT,traits>&
basic_ostream<charT,traits>::operator<< (basic_streambuf<charT,traits>* sb);
Edit
Note that this has changed in C++0x. Now, if the result of a conditional expression is an rvalue a temporary copy is always made. As objects of type ostream
are not copyable your code will not be valid in C++0x.
See here: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#446
You can use the conditional operator this way instead:
#include <fstream>
#include <iostream>
int main(int argc, char* argv[])
{
using namespace std;
ofstream file("tmp.txt");
int i=1;
(i > 1 ? file : cout) << cin.rdbuf();
return 0;
}
This compiles for me on gcc 4.4.3.
Not quite the one-liner you were looking for, I know.
NOTE: As Evan pointed out in his comment, this will result in the file being created even if not needed.
I can see two possibilities here:
- cout is of ostream type, the other (temporary) is ofstream, and they are not convertible to each other in any way
- even if they are convertible the result is a temporary rvalue and it will not bind to operator<< as it requires nonconst lvalue reference.
精彩评论