我有一个超载的
<<
用于别名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
限定符,使重载的 <<
全局化,但这些都不起作用。
如何修复这个错误,同时保持名称空间和类结构?
ADL 不考虑与别名关联的名称空间。 (这也没有意义。编译器是否应该记住所有具有别名的名称空间,然后突然认为所有在那里声明的函数都属于原始类型?)
让
Var
成为一个合适的独立类型。你要么让它成为一个包含 std::variant<bool, int>
的类,然后你可以实现和转发你需要的 std::variant
接口的部分,或者你让 Var
从 std::variant<bool, int>
公开继承,这样的好处是std::visit
仍然可以开箱即用。