mapbox / variant

C++11/C++14 Variant
BSD 3-Clause "New" or "Revised" License
371 stars 101 forks source link

Invalid copy constructor selected in some cases #122

Closed ukreator closed 7 years ago

ukreator commented 8 years ago

Simple code snippet to reproduce the issue:

struct X
{
    template <typename ValueType>
    X(const ValueType&)  {}
};

int main()
{
    mapbox::util::variant<X, int> a{123}; // init with int
    decltype(a) b = a;
    assert(a.which() == b.which());
}

boost::variant works fine in this case. This issue was originally spotted by random failures after replacing boost::variant with map box::variant. One of the types in the list was boost::any which has a templated constructor like in struct X above.

lightmare commented 8 years ago

This is caused by X being constructible from variant<Types...> and

template<typename T, ...> variant(T&&)

being a better match than

variant(variant<Types...> const& old)

when the actual argument is a non-const reference.

Possible solutions:

springmeyer commented 8 years ago

Thanks for reporting @ukreator and for the thoughts on solutions @lightmare. @artemp is out on vacation this week but I know he's planning a v1.1.x release soon after returning. I've assigned this to 1.1.3 to consider fixing before the next release.

artemp commented 7 years ago

@lightmare - thanks for digging! Adding an extra check in universal ctor and explicitly disabling passing variants in there is the winner:

&& !std::is_same<variant<Types...>, typename Traits::value_type>::value
artemp commented 7 years ago

@ukreator - Thanks for reporting and providing test-case !