Why does operator==(std::variant<T, U>, T) not work?

Advertisements

Consider the following:

#include <iostream>
#include <variant>

int main ()
{
    std::variant<int, float> foo = 3;
    if(foo == 3)
    {
        std::cout << "Equals 3\n";
    }
}

Godbolt demo here

This does not compile because of the foo == 3:

<source>:7:12: error: no match for 'operator==' (operand types are 'std::variant<int, float>' and 'int')
    7 |     if(foo == 3)
      |        ~~~ ^~ ~
      |        |      |
      |        |      int
      |        std::variant<int, float>
In file included from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/iosfwd:40,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/ios:38,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/ostream:38,
                 from /opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/iostream:39,
                 from <source>:1:
/opt/compiler-explorer/gcc-12.1.0/include/c++/12.1.0/bits/postypes.h:192:5: note: candidate: 'template<class _StateT> bool std::operator==(const fpos<_StateT>&, const fpos<_StateT>&)'
  192 |     operator==(const fpos<_StateT>& __lhs, const fpos<_StateT>& __rhs)
      |     ^~~~~~~~
// Many, many more rejected operator== candidates omitted

There’s a free function operator== that compares two std::variant<int, float>s. And there’s an implicit conversion from int to std::variant<int, float>; that’s how I was able to initialize foo in the first place. So why doesn’t this comparison compile?

Strictly speaking, I suppose there are a few related questions here. One is why this doesn’t already work, explaining how the rules for overload resolution apply to this section. And second is if there’s anything that can be done in user-written code to make this comparison work sensibly.

>Solution :

Neither parameter of that operator== overload is an undeduced context. So template argument deduction for the overload will fail if it fails in either parameter/argument pair.

Since int is not a std::variant, deduction will fail for the corresponding parameter/argument pair and so the template overload is not viable.

Implicit conversions are not considered when deducing template arguments. Types must (with few minor exceptions) match exactly.

Leave a ReplyCancel reply