使用重载的麻烦<< for std::variant

问题描述 投票:0回答:1

我有一个超载的

<<
用于别名
std::variant
A::Var
)。我还有一个在不同命名空间
C::Wrapper
中的类中定义的模板化函数,它只是将其参数转发给
std::ostream
.

我试图从

A
A::Foo
中定义的另一个函数调用它,但这给了我编译器错误。这个玩具示例如下。

#include <iostream>
#include <variant>

namespace C {
  struct Wrapper {
    template<typename T>
    auto& operator<<(T&& v) {
      std::cout << std::forward<T>(v);
      return *this;
    }
  };
}

namespace A {
  using Var = std::variant<bool, int>;

  auto& operator<<(std::ostream& os, const A::Var& v) {
    std::visit([&os](auto i) { os << i; }, v);
    return os;
  }

  struct Foo {
    void m() {
      C::Wrapper wrap;
      Var v{3};
      wrap << "hi"; // works
      wrap << v; // compiler error
    }
  };
}

int main() { 
  A::Foo a;
  a.m();
}

g++ -std=c++17
给出以下错误:

main.cpp: In instantiation of ‘auto& C::Wrapper::operator<<(T&&) [with T = std::variant<bool, int>&]’:
main.cpp:27:11:   required from here
main.cpp:8:15: error: no match for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘std::variant<bool, int>’)
    8 |     std::cout << std::forward<T>(v);

... many candidate functions none including my overloaded << for A::Var

我希望它能成功编译并在运行时打印

3
。我尝试使所有定义不一致,删除
const
限定符,使重载的
<<
全局化,但这些都不起作用。

如何修复这个错误,同时保持名称空间和类结构?

c++ c++17 perfect-forwarding argument-dependent-lookup
1个回答
0
投票

ADL 不考虑与别名关联的名称空间。 (这也没有意义。编译器是否应该记住所有具有别名的名称空间,然后突然认为所有在那里声明的函数都属于原始类型?)

Var
成为一个合适的独立类型。你要么让它成为一个包含
std::variant<bool, int>
的类,然后你可以实现和转发你需要的
std::variant
接口的部分,或者你让
Var
std::variant<bool, int>
公开继承,这样的好处是
std::visit
仍然可以开箱即用。

© www.soinside.com 2019 - 2024. All rights reserved.