Почему я не могу поместить эту перегрузку оператора в то же пространство имен, что и структура?
у меня есть следующий код:
#include <iostream>
#include <vector>
namespace X {
std::ostream& operator<<(std::ostream& os,const std::vector<double>& v){
for (int i=0;i<v.size();i++){os << v[i] << " ";}
return os;
}
namespace Y {
struct A {std::vector<double> x;};
std::ostream& operator<<(std::ostream& os,const A& a){
os << a.x << std::endl;
return os;
}
}
}
using namespace X;
int main(int argc, char** argv) {
std::vector<double> v(10,0);
std::cout << v << std::endl;
Y::A a;
std::cout << a << std::endl;
return 0;
}
первая перегрузка работает, но второй нет. По какой-то причине он не может найти первого. Я получаю сообщение об ошибке:
no match for 'operator<<' (operand types are 'std::ostream
{aka std::basic_ostream<char>}' and 'const std::vector<double>')
os << a.x << std::endl;
^
Я не понимаю, почему я получаю эту ошибку. Например что-то вроде этого, кажется, вполне уважительные:
namespace A {
void foo(){}
namespace B {
void bar(){foo();}
}
}
однако единственным способом исправить вышеуказанную проблему было поместить вторую перегрузку также В X. Почему невозможно иметь ее в том же пространстве имен, что и структура (т. е. X:: Y)?
PS: Я читал о ADL и я нашел некоторые связанные с этим вопросы (например,этой и этой, но то,что я понял из прочтения этого, должно работать.
3 ответов
в Argument Depended Lookup (или Koenig Lookup) компилятор добавляет в область видимости все символы, объявленные в родительских областях каждого параметр.
даже если Y
- это "пространство ребенка"X
, они не связаны с точки зрения ADL
. Первый из ваших параметров-тип, определенный в std::
пространство имен, а второй-локальный символ (определяется в том же пространстве имен, что и сама функция).
обратите внимание, что из-за причин, упомянутых выше, вы скорее всего получите еще одну ошибку в этой строке:
std::cout << v << std::endl;
когда компилятор не сможет найти operator<<
перегружены для std::vector<double>
(потому что он находится внутри namespace X
).
чтобы решить эту проблему, вы можете использовать:
using X::operator<<
внутри namespace Y
или переместить эту перегрузку.
Если вам интересно, почему foobar
пример работает: потому что ADL
(аргумент зависимый поиск) - это область параметров функций, а не сама функция. В foobar
код ADL
не применяется.
согласно другим ответам, я в конце концов пришел к выводу, что ADL оператора
сегодняшний урок: всегда пишите оператор
вот исправление:
#include <iostream>
#include <vector>
namespace X
{
std::ostream& operator<<(std::ostream& os,const std::vector<double>& v){
for (int i=0;i<v.size();i++){os << v[i] << " ";}
return os;
}
namespace Y
{
struct A
{
std::vector<double> x;
void write(std::ostream&os) const {
os << x << std::endl;
}
};
std::ostream& operator<<(std::ostream& os,const A& a)
{
a.write(os);
return os;
}
}
}
using namespace X;
int main(int argc, char** argv)
{
std::vector<double> v(10,0);
std::cout << v << std::endl;
X::Y::A a;
std::cout << a << std::endl;
return 0;
}
так просто:чтобы перегрузить функцию, перегруженная версия должна жить в том же nemaspace, иначе это совершенно другая функция. имя функции (для компилятора) - это полный путь от глобального пространства имен для самой функции.
::function_at_global_namespace();
Namespace::function_name(); // Some funtion within a namespace;
Namespace_1::function_name(); // Some other function within another namespace;
и
Standar std::ostream& operator<<
проживает в std
пространство имен, вы не перегружаете этот оператор, просто определяя anotherone в пространстве имен X
.
как указано @0x499602D2 вы должны использовать X::operator<<
в пространстве имен Y
для того, чтобы вызвать эту версию оператора.
std::ostream& std::operator<<
и std::ostream& X::operator<<
различные функции.
в следующем коде ни одна из версий foo не перегружается.
// What version of foo gets called? A::foo, or B::foo?
namespace A {
void foo(){cout << "A::foo" << endl;}
namespace B {
void foo(){ cout << "B::foo" << endl;}
void bar(){foo();}
}
}
namespace C { void foo(int a) { cout << "C:foo" << endl; } }