The canonical way to read lines from a text file is:
std::fstream fs("/tmp/myfile.txt");
std::string line;
while (std::getline(line, fs)) {
doThingsWith(line);
}
(no, it is not while (!fs.eof()) { getline(line, fs); doThingsWith(line); }!)
This works beacuse std::getline returns the stream argument by reference, and because:
in C++03, streams convert to void*, via an operator void*() const in std::basic_ios, evaluating to the null pointer value when the fail error flag is set;
see [C++03: 27.4.4] & [C++03: 27.4.4.3/1]
in C++11, streams convert to bool, via an explicit operator bool() const in std::basic_ios, evaluating to false when the fail error flag is set
see [C++11: 27.5.5.1] & [C++11: 27.5.5.4/1]
In C++03 this mechanism means the following is possible:
std::cout << std::cout;
It correctly results in some arbitrary pointer value being output to the standard out stream.
However, despite operator void*() const having been removed in C++11, this also compiles and runs for me in GCC 4.7.0 in C++11 mode.
How is this still possible in C++11? Is there some other mechanism at work that I'm unaware of? Or is it simply an implementation "oddity"?
I'm reasonably certain this is not allowed/can't happen in a conforming implementation of C++11.
The problem, of course, is that right now, most implementations are working on conforming, but aren't there completely yet. At a guess, for many vendors, this particular update is a fairly low priority. It improves error checking, but does little (or nothing) to enable new techniques, add new features, improve run-time efficiency, etc. This lets the compiler catch the error you've cited (some_stream << some_other_stream) but doesn't really make a whole lot of difference otherwise.
If I were in charge of updating a standard library for C++11, I think this would be a fairly low priority. There are other changes that are probably as easy (if not easier) to incorporate, and likely to make a much bigger difference to most programmers.
To use one of the examples you gave, if I were in charge of updating the VC++ standard library to take advantage of the compiler features added in the November CTP, my top priority would probably be to add constructors to the standard container types to accept initialization_lists. These are fairly easy to add (I'd guess one person could probably add and test them in under a week) and make quite an obvious, visible difference in what a programmer can do.
As late as GCC 4.6.2, the libstdc++ code for basic_ios is evidently still C++03-like.
I'd simply put this down to "they haven't gotten around to it yet".
By contrast, the libc++ (LLVM's stdlib implementation) trunk already uses operator bool().
This was a missed mini-feature buried in a pre-existing header. There are probably lots of missing error of omission and commission in pre-2011 components.
Really, if anyone comes up with things like this in gcc then it would do a world of good to go to Bugzilla and make a bug report. It may be a low priority bug but if you start a paper trail
I'll go out on a limb and extend this idea to all the other C++ compilers: clang, Visual Studio,etc.
This will make C++ a better place.
P.S. I entered a bug in Bugzilla.
Related
I've recently read about [[nodiscard]] in C++17, and as far as I understand it's a new feature (design by contract?) which forces you to use the return value. This makes sense for controversial functions like std::launder (nodiscard since C++20), but I wonder why std::move isn't defined like so in C++17/20. Do you know a good reason or is it because C++20 isn't finalised yet?
The MSVC standard library team went ahead and added several thousand instances of [[nodiscard]] since VS 2017 15.6, and have reported wild success with it (both in terms of finding lots of bugs and generating no user complaints). The criteria they described were approximately:
Pure observers, e.g. vector::size(), vector::empty, and even std::count_if()
Things that acquire raw resources, e.g. allocate()
Functions where discarding the return value is extremely likely to lead to incorrect code, e.g. std::remove()
MSVC does mark both std::move() and std::forward() as [[nodiscard]] following these criteria.
While it's not officially annotated as such in the standard, it seems to provide clear user benefit and it's more a question of crafting such a paper to mark all the right things [[nodiscard]] (again, several thousand instances from MSVC) and apply them -- it's not complex work per se, but the volume is large. In the meantime, maybe prod your favorite standard library vendor and ask them to [[nodiscard]] lots of stuff?
AFAIK P0600R1 is the only proposal for adding [[nodiscard]] to the standard library that was applied to C++20. From that paper:
We suggest a conservative approach:
[...]
It should not be added when:
[...]
not using the return value makes no sense but doesn’t hurt and is usually not an error
[...]
So, [[nodiscard]] should not signal bad code if this
[...]
doesn’t hurt and probably no state change was meant that doesn’t happen
So the reason is that the standard library uses a conservative approach and a more aggresive one is not yet proposed.
I am attempting to build a third-party C++ code base in which there are several places where an attempt is made to print an output stream to itself. This example demonstrates an expression of the same form:
#include <iostream>
int main(void) {
std::cout << std::cout << "Say what?" << std::endl;
return 0;
}
I find that without any options, g++ 4.8.5 accepts that code with zero complaints, but g++ 8.2.1 rejects it with a good old "no match for ‘operator<<’" error.
I understand the error. What I want to know is whether there is any reason to think that it was ever anything other than an error -- was there a C++ version or a widely used C++ compiler that would do something useful with such code? Although it accepts the code, g++ 4.8.5 is not such a compiler in my book because the program it builds evaluates the first << operation simply by outputting a hexadecimal number of unclear significance.
I have considered that it might be a simple typo, maybe magnified by copy & paste. For example, perhaps the second std::cout was an accidental duplicate of the first, or perhaps it was meant to be std::endl, instead. However, in a different source file in the same code base I see the same idiom of an output stream being printed to itself applied to objects of type std::stringstream, which suggests to me that it might be intentional.
My overall objective is to decide how best to fix the code.
What might be the intention of printing a stream to itself?
It is probably unintentional, or the intention itself was a mistake.
The difference between the GCC versions is the default dialect of C++ that they use. The newer GCC defaults to c++11 or newer. The program should compile with the newer compiler as long as you use a pre-C++11 dialect.
The change in C++11 was the removal of implicit conversion from std::basic_ios to void*. The purpose of this conversion was to check for failure state of the stream: null signified a failed stream while non-null signified a valid stream which allows the pattern if(stream >> input). In C++11 the conversion was replaced with explicit conversion to bool. Since the new conversion is explicit, it won't be applied to inserting a stream into stream. This was a backwards incompatible change which was presumably considered to not be a problem since the now-incompatible ways of using the conversion (such as the example) would have had no practical uses. In fact, it is useful to get a compilation error when doing something that has no practical use.
My overall objective is to decide how best to fix the code.
Probably just remove the insertion of cout into cout. If you're concerned that the output must remain same because it might be parsed by another program, then you can output any non-zero hex number to keep the output same for the sake of compatibility.
I've recently read about [[nodiscard]] in C++17, and as far as I understand it's a new feature (design by contract?) which forces you to use the return value. This makes sense for controversial functions like std::launder (nodiscard since C++20), but I wonder why std::move isn't defined like so in C++17/20. Do you know a good reason or is it because C++20 isn't finalised yet?
The MSVC standard library team went ahead and added several thousand instances of [[nodiscard]] since VS 2017 15.6, and have reported wild success with it (both in terms of finding lots of bugs and generating no user complaints). The criteria they described were approximately:
Pure observers, e.g. vector::size(), vector::empty, and even std::count_if()
Things that acquire raw resources, e.g. allocate()
Functions where discarding the return value is extremely likely to lead to incorrect code, e.g. std::remove()
MSVC does mark both std::move() and std::forward() as [[nodiscard]] following these criteria.
While it's not officially annotated as such in the standard, it seems to provide clear user benefit and it's more a question of crafting such a paper to mark all the right things [[nodiscard]] (again, several thousand instances from MSVC) and apply them -- it's not complex work per se, but the volume is large. In the meantime, maybe prod your favorite standard library vendor and ask them to [[nodiscard]] lots of stuff?
AFAIK P0600R1 is the only proposal for adding [[nodiscard]] to the standard library that was applied to C++20. From that paper:
We suggest a conservative approach:
[...]
It should not be added when:
[...]
not using the return value makes no sense but doesn’t hurt and is usually not an error
[...]
So, [[nodiscard]] should not signal bad code if this
[...]
doesn’t hurt and probably no state change was meant that doesn’t happen
So the reason is that the standard library uses a conservative approach and a more aggresive one is not yet proposed.
constexpr permits expressions which can be evaluated at compile time to be ... evaluated at compile time.
Why is this keyword even necessary? Why not permit or require that compilers evaluate all expressions at compile time if possible?
The standard library has an uneven application of constexpr which causes a lot of inconvenience. Making constexpr the "default" would address that and likely improve a huge amount of existing code.
It already is permitted to evaluate side-effect-free computations at compile time, under the as-if rule.
What constexpr does is provide guarantees on what data-flow analysis a compliant compiler is required to do to detect1 compile-time-computable expressions, and also allow the programmer to express that intent so that they get a diagnostic if they accidentally do something that cannot be precomputed.
Making constexpr the default would eliminate that very useful diagnostic ability.
1 In general, requiring "evaluate all expressions at compile time if possible" is a non-starter, because detecting the "if possible" requires solving the Halting Problem, and computer scientists know that this is not possible in the general case. So instead a relaxation is used where the outputs are { "Computable at compile-time", "Not computable at compile-time or couldn't decide" }. And the ability of different compilers to decide would depend on how smart their test was, which would make this feature non-portable. constexpr defines the exact test to use. A smarter compiler can still pre-compute even more expressions than the Standard test dictates, but if they fail the test, they can't be marked constexpr.
Note: despite the below, I admit to liking the idea of making constexpr the default. But you asked why it wasn't already done, so to answer that I will simply elaborate on mattnewport's last comment:
Consider the situation today. You're trying to use some function from the standard library in a context that requires a constant expression. It's not marked as constexpr, so you get a compiler error. This seems dumb, since "clearly" the ONLY thing that needs to change for this to work is to add the word constexpr to the definition.
Now consider life in the alternate universe where we adopt your proposal. Your code now compiles, yay! Next year you decide you to add Windows support to whatever project you're working on. How hard can it be? You'll compile using Visual Studio for your Windows users and keep using gcc for everyone else, right?
But the first time you try to compile on Windows, you get a bunch of compiler errors: this function can't be used in a constant expression context. You look at the code of the function in question, and compare it to the version that ships with gcc. It turns out that they are slightly different, and that the version that ships with gcc meets the technical requirements for constexpr by sheer accident, and likewise the one that ships with Visual Studio does not meet those requirements, again by sheer accident. Now what?
No problem you say, I'll submit a bug report to Microsoft: this function should be fixed. They close your bug report: the standard never says this function must be usable in a constant expression, so we can implement however we want. So you submit a bug report to the gcc maintainers: why didn't you warn me I was using non-portable code? And they close it too: how were we supposed to know it's not portable? We can't keep track of how everyone else implements the standard library.
Now what? No one did anything really wrong. Not you, not the gcc folks, nor the Visual Studio folks. Yet you still end up with un-portable code and are not a happy camper at this point. All else being equal, a good language standard will try to make this situation as unlikely as possible.
And even though I used an example of different compilers, it could just as well happen when you try to upgrade to a newer version of the same compiler, or even try to compile with different settings. For example: the function contains an assert statement to ensure it's being called with valid arguments. If you compile with assertions disabled, the assertion "disappears" and the function meets the rules for constexpr; if you enable assertions, then it doesn't meet them. (This is less likely these days now that the rules for constexpr are very generous, but was a bigger issue under the C++11 rules. But in principle the point remains even today.)
Lastly we get to the admittedly minor issue of error messages. In today's world, if I try to do something like stick in a cout statement in constexpr function, I get a nice simple error right away. In your world, we would have the same situation that we have with templates, deep stack-traces all the way to the very bottom of the implementation of output streams. Not fatal, but surely annoying.
This is a year and a half late, but I still hope it helps.
As Ben Voigt points out, compilers are already allowed to evaluate anything at compile time under the as-if rule.
What constexpr also does is lay out clear rules for expressions that can be used in places where a compile time constant is required. That means I can write code like this and know it will be portable:
constexpr int square(int x) { return x * x; }
...
int a[square(4)] = {};
...
Without the keyword and clear rules in the standard I'm not sure how you could specify this portably and provide useful diagnostics on things the programmer intended to be constexpr but don't meet the requirements.
Consider this program:
#include <iostream>
int main()
{
delete std::cout;
}
AFAIK the conversion function operator void* () const has been removed from C++11. So, this program should fail in compilation on a C++11 compiler. Ya, its true that both g++ 4.8.1 & 4.9.2 gives diagnosis (in the form of warning that deleting void* is undefined & that's also the good thing). But shouldn't this program fail in compilation because removal of that conversion function due to which all stream object could be implicitly converted to void* in C++98 & C++03?. Is this bug? It seems bit surprising that they still not have implemented this change.
I've tried this program in g++ 4.9.2(that supports C++14) but it gives warning not compiler error. Ideone compiler gives me an error as expected. (See live demo here)
It has nothing to do with the compiler, its a library issue. libstdc++ has lots of incompatibilities with C++11, of which this is just one. They are making breaking changes in 5 and up though iirc.
In short, it's neither a bug nor a compiler issue.
This is a bug in the standard library (if you view it as an implementation of the C++11/14 standard library rather than C++98/03).
It's sort of a compiler issue as well though. Specifically, removing the conversion to void * depends on adding a conversion directly to bool--but that, in turn, depends on adding "contextual conversion" to the compiler.
gcc 4.8 did implement a form of contextual conversion, but not the form that was accepted into the standard. Although the specific changes to contextual conversion wouldn't directly impact this use of contextual conversion, it does point to the fact that the definition of contextual conversion was still being tweaked as these compilers were being written.
The sequence in which things (at least normally) happen is that first the specification is solidified. Then the compiler implements it. Then the standard library puts it to use.
In this case the specification was still changing fairly shortly before the compiler was released. Therefore, the standard library didn't (and practically speaking, couldn't) use it.
By the time of 4.9, the specification was solid, and the compiler implemented the final version of contextual conversion, but it hadn't been around long enough to be put to use in the standard library yet.