оператор перегрузки << против пространств имен - PullRequest
3 голосов
/ 01 августа 2011

У меня проблема с перегрузкой оператора << в сочетании с пространствами имен. Я прочитал соответствующие посты, но до сих пор не понимаю, что происходит в моем случае .. </p>

Следующий код компилирует OK:

файл test_matrix.hpp:

#ifndef TEST_MATRIX_HPP
#define TEST_MATRIX_HPP

#include <boost/numeric/ublas/matrix.hpp>
#include <boost/numeric/ublas/matrix_expression.hpp>
namespace ublas = boost::numeric::ublas; // shortcut name

namespace VecMat {
    typedef ublas::matrix<double> MatrixD; // matrix of doubles

    template<class MT>
    std::ostream & operator<< (std::ostream & os,
                               const ublas::matrix_expression<MT> & M)
    {
        // Note: the matrix_expression<MT> has only one method "()", which
        // returns "& MT" or "const & MT" - a ref. to the included matrix object.
        typename MT::const_iterator1 it1;
        typename MT::const_iterator2 it2;
        for (it1 = M().begin1(); it1 != M().end1(); ++it1) {
            for (it2 = it1.begin(); it2 != it1.end(); ++it2) {
                os << *it2 << "\t";
            }
        os << std::endl;
        }
        return os;
    }
}; // namespace VecMat
#endif

файл test_oper.cpp:

#include "test_matrix.hpp"
using std::cout;
using std::endl;
using VecMat::MatrixD;
using VecMat::operator<<;

// ---------------------------------------------------------------------------
// would be in a header file
void test1 ();
namespace Main {
    void test2 ();
}
// ---------------------------------------------------------------------------

void test1 ()
{
    MatrixD X(10,3);
    VecMat::operator<<(cout << endl, X) << endl;
    cout << "X =" << endl << X << endl;
}

void Main::test2 ()
{
    MatrixD X(10,3);
    VecMat::operator<<(cout << endl, X) << endl;
    cout << "X =" << endl << X << endl;
}

Обратите внимание, что необходима строка с использованием VecMat :: operator <<; </em> - без нее я получаю сообщение об ошибке в последней строке test1 () (при использовании gcc 4.5) :

test_oper.cpp || В функции 'void test1 ()': |
test_oper.cpp | 22 | ошибка: нет совпадения для 'operator <<' in '((std :: basic_ostream *) std :: operator << </p>

Разве компилятор не должен сам находить оператор, используя ADL, поскольку аргумент имеет тип VecMat :: MatrixD ?

Моя основная проблема, однако, начинается, когда я добавляю новый класс с собственным оператором << в пространство имен <em>Main :

файл test_other.hpp:

#ifndef TEST_OTHER_HPP
#define TEST_OTHER_HPP
#include <ostream>

namespace Main {
    class Foo {
        int n;
    };
    std::ostream & operator<< (std::ostream & os, Foo const & foo);
}
#endif

Если я затем "#include" test_other.hpp "" из любого из двух исходных файлов, файл .cpp не будет компилироваться с той же ошибкой, что и выше, только в последней строке test2 ( )

test_oper.cpp || В функции 'void Main :: test2 ()': | test_oper.cpp | 29 | ошибка: нет совпадения для 'operator <<' in '((std :: basic_ostream *) std :: operator << </p>

Если я помещу Foo в другое пространство имен (либо VecMat , либо в новое), оно компилируется в порядке. Означает ли это, что компилятор сначала просматривает Main , находит там один оператор << (для Foo) и поэтому прекращает поиск и жалуется, что нашел неправильный оператор? Опять же, я бы подумал, что сначала он будет изучать <em>VecMat , поскольку аргумент имеет тип VecMat :: MatrixD ?

Буду признателен как за объяснение происходящего, так и за рекомендацию, как решить его самым чистым способом.

Большое спасибо.
Михал

PS : я разместил вопрос также в другом месте, и там было предложено (http://www.cplusplus.com/forum/general/47766/#msg259246) добавить , используя VecMat :: operator <<; </em> также внутри строки Main namespace. Это решает это, но я все еще хотел бы знать, зачем мне эти строки и является ли это лучшим / рекомендуемым решением.

1 Ответ

1 голос
/ 01 августа 2011

typedef не вводит новый тип. Таким образом, VecMat::MatrixD не является новым типом, это псевдоним boost::numeric::ublas::matrix<double>, поэтому связанные пространства имен, используемые в ADL, относятся к boost::numeric::ublas::matrix<double>.

...