Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11 issues when moving from Visual Studio 2010 to 2012

I'm trying to port my project from Visual Studio 2010 to Visual Studio 2012. In my code I have some file handling that looks like this:

auto fileDeleter = [](FILE* f) { fclose(f); };

unique_ptr<FILE, decltype(fileDeleter)> fMinute(
    fopen(minuteLogName.c_str(), "w"), fileDeleter);


unique_ptr<FILE, decltype(fileDeleter)> fIndividual(
    fopen(individualLogName.c_str(), "w"), fileDeleter);

if (!fMinute || !fIndividual) {
    throw Exceptions::IOException("One of the log files failed to open",
                                  __FUNCTION__);
}

This built with no issues in 2010, but in 2012 it fails on the conditional with:

error C2678: binary '!' : no operator found which takes a left-hand operand of type > 'std::unique_ptr<_Ty,_Dx>' (or there is no acceptable conversion)
...
could be 'built-in C++ operator!(bool)'

The C++11 standard specifies that unique_ptr has a bool operator to allow you to do quick checks like I have above. Stranger yet, VS2012's unique_ptr definition has this very operator:

_OPERATOR_BOOL() const _NOEXCEPT
{   // test for non-null pointer
    return (this->_Myptr != pointer() ? _CONVERTIBLE_TO_TRUE : 0);
}

But I get that error upon compilation. Why?

Yes, I could just be using ofstream instead, but that's besides the point.

like image 446
Matt Kline Avatar asked Oct 20 '12 22:10

Matt Kline


People also ask

Does Visual Studio support C 11?

Modern C++ SupportEnjoy support for C++11, C++14 and many C++17 features with market leading performance, build throughput and security.

Is Visual Studio 2012 still supported?

Visual Studio 2012: support ends on January 10, 2023 for the IDE and its associated products, runtimes, and components. We recommend users upgrade to a newer version of Visual Studio. Visual Studio 2017: mainstream support ends April 12, 2022, and the product will transition to extended support until April 2027.

What version of C does Visual Studio use?

The /std:c11 option enables ISO C11 conformance. It's available starting in Visual Studio 2019 version 16.8. The /std:c17 option enables ISO C17 conformance. It's available starting in Visual Studio 2019 version 16.8.

Which is the most stable version of Visual Studio?

Visual Studio 2022 is the best Visual Studio ever. Our first 64-bit IDE makes it easier to work with even bigger projects and more complex workloads. The stuff you do every day—like typing code and switching branches—feels more fluid more responsive.


2 Answers

To build on what BigBoss said, C++11 requires that std::unique_ptr use explicit operator bool() noexcept, which solves the whole implicit conversion to bool problem. Except... VC2012 doesn't support explicit operators yet. Therefore, they have to use the safe-bool idiom.

While the safe-bool idiom is good, it can have flaws (which is why explicit operator bool() exists), depending on how you implement the idiom. And you apparently ran across one of them in VC2012. Reconfiguring your test, with !(fMinute && fIndividual), should solve it.

But either way, it's a Visual Studio bug. Since the behavior changed, you should file a bug report even if you do manage to find a way around it.

like image 103
Nicol Bolas Avatar answered Sep 17 '22 21:09

Nicol Bolas


You can use if (!(fMinute && fIndividual) ) instead of if (!fMinute || !fIndividual). C++ say that they are convertible to bool, but operator bool usually create problems, for example you may have a function that accept int, if your class have an operator bool then it is convertible to int and you can pass it to this function, but for example in our case unique_ptr never intended to be used as an int, so many developers never use operator bool directly but instead write an operator that can be used as a bool in conditional expressions but it is not actually bool!

struct bool_convertible {
    typedef void (*convertible_to_bool)();
    static void convertible_to_true();
    operator convertible_to_bool () const {
        return test() ? &convertible_to_true : nullptr;
    }
};

Using this technique I may have bool_convertible c; if( c ) {...} but I can't have

void test_int( int );
bool_convertible c;
test_int( c );
like image 24
BigBoss Avatar answered Sep 18 '22 21:09

BigBoss