Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to disable implicit conversion from pointer types to bool when constructing an std::variant?

Consider the following:

struct foo {
};

struct bar {
};

int main()
{
    foo f;
    bar b;
    std::variant<foo*, bool> v;
    v = &b; // compiles in Visual Studio 19 v16.7.3
}

As discussed in comments, I believe the above is legal C++17. There is a proposal, P0608R3, that was accepted into the standard addressing this kind of surprising behavior, but it was accepted in 2018 (at the San Diego meeting) and thus applies to C++20 not C++17. Further P0608R3 is not currently implemented in Visual Studio, even when compiling to the C++20 preview.

What is the best / least verbose way to make creation of this variant from a pointer that points to a non-foo a compile time error? I believe the following works but is a lot of boilerplate if the variant contains several items.

struct foo {
};

struct bar {
};

using variant_type = std::variant<foo*, bool>;
struct var_wrapper : public variant_type
{
    var_wrapper(foo* v = nullptr) : variant_type(v)
    {}

    var_wrapper(bool v) : variant_type(v)
    {}

    template<typename T>
    var_wrapper(T*) = delete;
};

int main()
{
    foo f;
    bar b;

    var_wrapper vw;
    vw = &f; // fine
    vw = true; // fine
    vw = &b; // compile time error
}

Am I missing some simpler way?

like image 464
jwezorek Avatar asked Oct 07 '20 18:10

jwezorek


1 Answers

Another solution is to introduce another bool wrapper that doesn't construct from anything except from bool:

#include <variant>

struct foo {};
struct bar {};

struct StrongBool {
    bool value = false;

    StrongBool() noexcept = default;
    StrongBool(bool b) noexcept : value(b) {}

    template<class T>
    StrongBool(T) = delete;
};

int main() {
    foo f;
    bar b;
    std::variant<foo*, StrongBool> v;
    v = true;
    v = &f;
    v = &b; // fails to compile
} 

Regardless, limiting acceptable initializers requires introducing type wrappers with user-defined constructors.

like image 164
Maxim Egorushkin Avatar answered Oct 10 '22 06:10

Maxim Egorushkin