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.
Modern C++ SupportEnjoy support for C++11, C++14 and many C++17 features with market leading performance, build throughput and security.
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.
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.
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.
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.
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 );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With