此问题在此处已有答案:
Argument dependent name lookup and typedef(4个答案)
ADL with typedefs from another namespace(7个答案)
Why does arguement dependent lookup not work for type aliasing in c++?(1个答案)
Argument-dependent lookup behaving unexpectedly on types aliased from another namespace(1个答案)
Argument Dependent Lookup and stream operators overloading(1个答案)
4天前关闭。
我为别名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
限定符,使重载的<<
成为全局的,但这些都不起作用。
我怎样才能修正这个错误,同时保留命名空间和类结构?
- 更新 *:
通过在全局名称空间中定义<<
,代码可以使用gcc进行编译,如下所示,但它会因clang而失败:
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;
}
namespace A {
struct Foo {
void m() {
C::Wrapper wrap;
A::Var v{3};
wrap << "hi"; // works
wrap << v; // compiler error
}
};
} // namespace A
clang++ -std=c++17
错误:
main.cpp:7:15: error: call to function 'operator<<' that is neither visible in the template definition nor found by argument-dependent lookup
std::cout << std::forward<T>(v);
^
main.cpp:28:10: note: in instantiation of function template specialization 'C::Wrapper::operator<<<std::variant<bool, int> &>' requested here
wrap << v; // compiler error
^
main.cpp:17:7: note: 'operator<<' should be declared prior to the call site
auto &operator<<(std::ostream &os, const A::Var &v) {
^
1 error generated.
为什么它可以和gcc一起使用,而不能和clang一起使用?
1条答案
按热度按时间68bkxrlz1#
参数相关查找(ADL)不考虑与别名关联的名称空间(这也没有意义,编译器是否应该记住所有名称空间都有
std::variant<bool, int>
的别名,然后突然认为所有声明在那里的函数都属于std::variant<bool, int>
?)使
Var
成为一个合适的独立类型。要么使它成为一个具有私有std::variant<bool, int>
成员的类,然后可以实现和转发所需的std::variant
接口部分,要么让Var
从std::variant<bool, int>
公开继承并继承构造函数,这样做的好处是std::visit
仍然可以开箱即用。然后,当您将
<<
应用于Var
时,ADL将考虑命名空间A
中的operator<<
重载。