booleanc++builderc++builder-10-seattle

Converting a Variant to bool


How do you convert a Variant to bool in C++Builder 10?

In the old bcc32 compiler, I used the following code to check whether some generic TComponent was enabled:

if ((bool)GetPropValue(c, "Enabled", false))
    do_something();

However, after upgrading to C++Builder 10 and enabling the new Clang-based compiler, I get the following error:

[CLANG Error] VclHelpers.cpp(1375): ambiguous conversion for C-style cast from 'System::Variant' to 'bool'

The full compiler messages indicate that 36 of Variant's conversion operators are considered legal candidates: operator double(), operator wchar_t*, etc.


Solution

  • The problem is that Variant provides too many conversion operators. In particular, the following operators make conversion to bool ambiguous:

    __fastcall operator bool() const;
    __fastcall operator signed char*();
    __fastcall operator unsigned char*();
    // etc. - Variant has similar operators for short, int, long, float, double...
    // It calls these "by ref" conversions.
    

    As I understand it, non-const overloads are normally preferred to const overloads, but with >1 alternative for non-const convertible-to-bool pointer conversions as well as a const bool conversion, the conversion is ambiguous.

    It's probably a mistake for Variant to have its conversions designed in such a way that they can't be used without ambiguity, but with help from @user2672165's and @Remy Lebeau's comments, there are several workarounds:

    // Convert to int instead of bool.
    if ((int)GetPropValue(c, "Enabled", false)) {}
    
    // Make the Variant const, to avoid the ambiguous non-const conversions.
    if (const_cast<const Variant>(GetPropValue(c, "Enabled", false))) {}
    
    // Explicitly invoke the desired conversion operator.
    if (GetPropValue(CheckBox1, "Enabled", false).operator bool()) {}
    
    // Use TRttiProperty instead of Variant.
    RttiContext ctx;
    if (ctx.GetType(c->ClassType())->GetProperty("Enabled")->GetValue(c).AsBoolean()) {}