3

The code below compiles in VS 2012 but not in VS 2013

std::ofstream stm;
if(stm != NULL)
{
}

In VS 2013 you get this compilation error:

binary '!=' no operator found which takes a left-hand operand of type 'std::ofstream' (or there is no acceptable conversion)

I looked at the headers and in <xiobase> and I found the following:

VS2012

ios_base::operator void *() const;

VS2013

operator void *() const has been removed and the operator bool with explicit was added instead:

ios_base::explicit operator bool() const;

Now my questions:

  1. I couldn't find any information about this change in the internet. Do you know if there is an official article about this change anywhere?
  2. I have legacy code where if(stm != NULL) is used a lot. For unrelated reasons it's preferable not to change the code. Is there a way to make it compile in VS 2013 without changing it? I couldn't find any conditional compilation directives that could restore operator void* or remove explicit from operator bool().

PS: gcc 4.9.0 still has operator void*() const. So it will not have this problem.

UPDATE:

To make my legacy code compile I implemented the following overloads as it was suggested:

#include <xiosbase>

bool operator==(const std::basic_ios<char, char_traits<char>> &stm, int null_val)
{
    return static_cast<bool>(stm) == null_val;
}

bool operator==(int null_val, const std::basic_ios<char, char_traits<char>> &stm)
{
    return operator==(stm, null_val);
}

bool operator!=(int null_val, const std::basic_ios<char, char_traits<char>> &stm)
{
    return !operator==(stm, null_val);
}

bool operator!=(const std::basic_ios<char, char_traits<char>> &stm, int null_val)
{
    return !operator==(stm, null_val);
}

In my case the char value type was enough and the second parameter is int because something that is not NULL is not supported anyway.

evpo
  • 2,436
  • 16
  • 23
  • 4
    Well that change is part of the C++11 specification, so it should be pretty easy to find articles on it. If nothing else by reading a draft specification. – Some programmer dude Apr 23 '14 at 06:37
  • @JoachimPileborg yes, http://en.cppreference.com/w/cpp/io/basic_ios/operator_bool is a very useful article. It says that operator void *() "until C++11" and explicit operator bool() "since C++11". So it looks like it's a known change – evpo Apr 23 '14 at 06:41
  • I doubt GCC 4.9's libstdc++ has `operator void*` when compiling in C++11 mode. I can't find it in [the GCC 4.9 `ostream` header](http://gcc.gnu.org/viewcvs/gcc/branches/gcc-4_9-branch/libstdc%2B%2B-v3/include/std/ostream?revision=209304&view=markup), which contains `operator bool`... – rubenvb Apr 23 '14 at 08:19
  • @rubenvb Look at this demo http://goo.gl/yIHOXx – evpo Apr 23 '14 at 08:21
  • Huh, that looks erronous... C++11 `27.5.5.1` has no `operator void*() const` in `std::basic_ios`. But [VS2013 still has it](http://msdn.microsoft.com/en-us/library/kby3a433.aspx), although they show an example where the address of the stream object is taken. – rubenvb Apr 23 '14 at 08:25
  • Also relevant is [this mailing list discussion](http://gcc.1065356.n5.nabble.com/PATCH-PR56193-Wrong-test-operator-for-basic-ios-in-C-11-td911582.html), and [this patch](http://gcc.gnu.org/viewcvs/gcc/branches/gcc-4_9-branch/libstdc%2B%2B-v3/include/bits/basic_ios.h?r1=195849&r2=195939) seems to the wrong way around. – rubenvb Apr 23 '14 at 08:31

3 Answers3

6

C++11 requires some boolean conversions to be explicit that used to be implicit. This is noted in Appendix C about compatibility with C++03:

C.2.15 Clause 27: Input/output library [diff.cpp03.input.output]

27.7.2.1.3, 27.7.3.4, 27.5.5.4

Change: Specify use of explicit in existing boolean conversion operators

Rationale: Clarify intentions, avoid workarounds.

Effect on original feature: Valid C++ 2003 code that relies on implicit boolean conversions will fail to compile with this International Standard. Such conversions occur in the following conditions:

  • passing a value to a function that takes an argument of type bool;
  • using operator== to compare to false or true;
  • returning a value from a function with a return type of bool;
  • initializing members of type bool via aggregate initialization;
  • initializing a const bool& which would bind to a temporary.
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • In MSVC 2015 `if(stm)` compiles, but `if(stm == true)` fails. How come only the second one qualifies as 'implicit boolean conversion'? Could this be an MSVC bug? – Ofek Shilon Nov 27 '16 at 08:46
1

If you have a lot of legacy code, you could probably add a custom operator!= (and operator==) function which takes the correct arguments:

bool operator!=(std::basic_ios const& ios, const void* ptr);
bool operator!=(const void* ptr, std::basic_ios const& ios);
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Overloading operators for `std::` types, is that even allowed? – MSalters Apr 23 '14 at 09:25
  • 1
    @MSalters We do it all the time when making an inserter/extractor (`operator<<()`/`operator>>()`). Why should it not be? – David G Apr 23 '14 at 12:33
  • @0x499602D2: Because in that case, the overload includes one of your own types. That obviously can't collide with a `std::` provided overload. – MSalters Apr 23 '14 at 14:16
0

The operator is defined in section 27.5.5 Class template basic_ios.

27.5.5.1 Overview

explicit operator bool() const;

And then

27.5.5.4 basic_ios flags functions

explicit operator bool() const;

Returns: !fail().

Community
  • 1
  • 1
Marius Bancila
  • 16,053
  • 9
  • 49
  • 91