Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Surprising behavior of variant with is_constructible, is_assignable and is_convertible traits #102

Open
eido79 opened this issue Nov 7, 2022 · 1 comment

Comments

@eido79
Copy link

eido79 commented Nov 7, 2022

is_constructible, is_assignable and is_convertible return surprising result under some conditions, suggesting that a variant might be "compatible" with a certain type, while it is, in fact, not.

See https://godbolt.org/z/zzG8WaKP8 for a minimal example.

@eido79
Copy link
Author

eido79 commented Nov 8, 2022

Simplifying the problem even further (https://godbolt.org/z/Kc5nrqaP9)

struct X{};
struct test1
{
    test1() = default;
    test1(X) {}
};
struct test2
{
    test2() = default;
    explicit test2(X) {}
};
struct test3
{
    test3() = default;
    test3(X) {}
};
void test_variant()
{
    using boost::variant;
    static_assert(std::is_constructible_v<variant<test1>, X>); // OK
    variant<test1> v1(X{}); // OK

    static_assert(std::is_constructible_v<variant<test1, test2>, X>); // OK
    variant<test1, test2> v2(X{}); // OK: X can be converted to test1, but not test2 as test2(X) is explicit

    static_assert(std::is_constructible_v<variant<test2>, X>); // Not OK because...
    //variant<test2> v3(X{}); // ... it doesn't compile: test2(X) is explicit

    static_assert(std::is_constructible_v<variant<test1, test3>, X>); // Not OK because...
    variant<test1, test3> v4(X{}); // ... it doesn't compile: ambiguous
}

I think the issue is in the definition of is_variant_constructible_from and is_constructible_ext, which are used in conversion construction and assignment operator. The documentation states that

T must be unambiguously convertible to one of the bounded types (i.e., T1, T2, etc.).

(emphasis mine).

But is_variant_constructible_from via is_constructible_ext checks if at least one of the bounded types is constructible from T, hence std::is_constructible returning true for ambiguous conversions or explicit constructor.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant