Question

I'm trying to clean up some code with ternary operators and I'm running into some compiler errors i can't make sense of.

The code I had before looks like this and runs fine.

if(!inFile.good())
     throw -2;
getline(inFile, inLine);

And I'm trying to clean it up using this code instead.

(inFile.good()) ? getline(inFile, inLine) : throw -2;

But I'm getting the following errors.

g++ -w -o test orange_test.cpp
In file included from orange_test.cpp:4:
In file included from /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/iostream:39:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/streambuf:558:31: error: base class 'std::__1::ios_base' has private
  copy constructor
_LIBCPP_EXTERN_TEMPLATE(class basic_ios<char>)
                          ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/__config:462:54: note: expanded from macro '_LIBCPP_EXTERN_TEMPLATE'
#define _LIBCPP_EXTERN_TEMPLATE(...) extern template __VA_ARGS__;
                                                 ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/ios:305:5: note: declared private here
ios_base(const ios_base&); // = delete;
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/istream:1706:31: note: implicit default copy constructor for
  'std::__1::basic_ios<char>' first required here
_LIBCPP_EXTERN_TEMPLATE(class basic_istream<char>)
                          ^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/c++/v1/__config:462:54: note: expanded from macro '_LIBCPP_EXTERN_TEMPLATE'
#define _LIBCPP_EXTERN_TEMPLATE(...) extern template __VA_ARGS__;
                                                 ^
./orange_model.hpp:145:23: note: implicit default copy constructor for 'std::__1::basic_istream<char>' first required here
                            (inFile.good()) ? getline(inFile, inLine) : throw -2;
                                              ^
1 error generated.
make: *** [main] Error 1

I can't make any sense of it. Is there some limitation of ternary operators or scope that I'm not aware of? Any help or insight would be greatly appreciated. Thanks in advance, Max

Edit

From looking at it the main error seems to be

error: base class 'std::__1::ios_base' has private copy constructor

It's complaining about the std::getline(inFile, inLine) function.

Answer

This code gets it running smoothly. Thanks everyone!

inFile.good() ? (void) getline(inFile, inLine) : throw -2;
Was it helpful?

Solution

The ternary operator has a special rule when one side is a throw. Part of that rule is that the result always will be a temporary rvalue, never a reference. So the compiler needs to make a copy of the getline() return value, and this fails because the stream is non-copyable.

You can explicitly discard the getline() return value in order to avoid the copy attempt:

inFile? (void)getline(inFile, inLine) : (throw -2);

I don't agree with your cleanup attempt, however. The original is easier to understand and maintain.

Also, did you mean to test goodness of inFile before or also after getline()? You could do

getline(inFile, inLine) || (throw -2);

which is idiomatic is some other languages, like perl's something or die "Error message"

OTHER TIPS

If you're set on the ternary conditional (which I personally don't agree with), you have to prevent the throw() part from causing a copy (see Ben's answer), which you can do by making that part evaluate to a reference, just as the getline part does, with the comma operator:

inFile.good() ? getline(inFile, inLine) : (throw -2, inFile);

Where the error comes in is that the copy-constructor for std::istream is private to prevent copying, causing that attempted copy to fail. Just having the throw without the comma operator would work with, e.g., 1 instead of the getline call.

getline returns the istream & you pass in (inFile), and the last part evaluates the throw, discards the result, and evaluates and uses inFile as its final value. Except here once you do the throw, execution does not continue to evaluating inFile, so it won't have an effect on the running code's logic.

You are not supposed to use the "return-value" of a throw.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top