Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

explicit conversion operator vs get< T >() function for std::variant

What are the downsides to make a part of std::variant class an explicit conversion (to alternative) operator overloadings set in addition to (or even instead of) get< T >() free functions (p.568 of the draft)?

template<class... Types>
class variant
{
    template<class T>
    explicit operator const T& () const&;
    template<class T>
    explicit operator T& () &;
    template<class T>
    explicit operator const T&& () const &&;
    template<class T>
    explicit operator T&& () &&;
};

Is it unsafe in some contexts? Why do we need free get() function (namely, "type" version, not "index" one), when variant exposes a value semantic (cite from the draft):

A variant object holds and manages the lifetime of a value.

Isn't it enough to make a variant explicitly convertible to alternative, but still implicitly constructible from an alternative?

I know, the uniformity of the interface is good thing (I remember we need get< I >() along with get< T >()), but I think it is more natural way to get containing alternative value simply by converting to it, rather then applying some function specialization to variant instance.

like image 832
Tomilov Anatoliy Avatar asked Aug 11 '26 15:08

Tomilov Anatoliy


1 Answers

I can think of a few downsides:

  • std::variant can hold cv void, but conversion functions returning cv void& and cv void&& would be illegal, and conversion functions to cv void are never called ([class.conv.fct]/1);
  • It is possible for a std::variant to hold a type that can also be constructed from it, e.g.: std::variant<std::monostate, std::any> v; std::any a{v}; - what should happen in this case?

In addition, currently it is possible to take a function returning T, convert it to a function returning std::variant<T, U> and expect the compiler to detect all cases where code needs to be changed; with a conversion function to T any cases where code was copying or binding a reference to T would result in a bug:

int f();
int i{f()};    // OK

// f() changes to:
std::variant<int, std::string> f();
int i{f()};    // can now throw std::bad_variant_access
like image 195
ecatmur Avatar answered Aug 14 '26 05:08

ecatmur