Problems with C ++ 11 when migrating from Visual Studio 2010 to 2012

I am trying to migrate my project from Visual Studio 2010 to Visual Studio 2012. In my code, I have file processing 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__); } 

It was built without problems in 2010, but in 2012 it fails on condition:

error C2678: binary '!': operator not found that accepts the left operand of type> 'std :: unique_ptr <_Ty, _Dx>' (or there is no acceptable conversion)
...
may be a "built-in C ++ operator! (bool)"

The C ++ 11 standard states that unique_ptr has a bool operator so that you can perform quick checks like above. Even stranger, the definition of VS2012 unique_ptr has this same operator:

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

But I get this error when compiling. Why?

Yes, I could just use ofstream instead, but that's beyond the point.

+7
source share
3 answers

To build on what BigBoss said, C ++ 11 requires std::unique_ptr use the explicit operator bool() noexcept , which solves all the implicit conversion to the bool problem. Except ... VC2012 does not yet support explicit statements. Therefore, they should use a safe idiom .

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

But in any case, this is a Visual Studio error. As the behavior has changed, you should report an error even if you can find a way around it.

+6
source

You can use if (!(fMinute && fIndividual) ) instead of if (!fMinute || !fIndividual) . C ++ say they convert to bool, but operator bool usually creates problems, for example, you can have a function that accepts int , if your class has an operator bool , then it is converted 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 the operator bool directly, but instead write an operator that can be used as bool in conditional expressions, but this is not really 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 method, I can have bool_convertible c; if( c ) {...} bool_convertible c; if( c ) {...} but I cannot have

 void test_int( int ); bool_convertible c; test_int( c ); 
+1
source

In the recent C ++ 11 standard, std :: unique_ptr does not have an operator! , only explicit conversion operator

 explicit operator bool() const; 

However, the built-in unary logical negation operator ! , contextually converts its argument to bool in accordance with 5.3.1 / 9:

The operand of the logical negation operator ! converted by context to bool (section 4); its value is true if the converted operand is false and false otherwise

Context conversion in bool will use an explicit conversion operator, if one is available. Thus, your code is expected to work under C ++ 11 rules. You should probably report a bug to Microsoft. Regardless of whether they support explicit conversion operators or not, it does not matter.

As a workaround, try the following:

 if (!fMinute.get() || !fIndividual.get()) { .... 
+1
source

All Articles