为什么 operator==(std::variant<T, U>, T) 不起作用?

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

考虑以下几点:

#include <iostream>
#include <variant>

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

Godbolt demo here

由于 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

有一个免费函数 operator== 可以比较两个 std::variant<int, float>。并且存在从 intstd::variant<int, float> 的隐式转换;这就是我首先能够初始化 foo 的方式。那么为什么这个比较不编译?

严格来说,我想这里有几个相关的问题。一个是为什么这 already 不起作用,解释了重载决议规则如何适用于本节。其次是是否可以在用户编写的代码中做任何事情来使这种比较合理地进行。

operator== 重载的两个参数都不是未推导的上下文。因此,如果在 parameter/argument 对中失败,则重载的模板参数推导将失败。

由于 int 不是 std::variant,因此对应的 parameter/argument 对的推导将失败,因此模板重载不可行。

推导模板参数时不考虑隐式转换。类型必须(除了少数小例外)完全匹配。