重载 operator<< 与命名空间

4
我在运用命名空间时,遇到了与重载运算符<<相关的问题。我已经阅读了相关帖子,但仍然不理解我的情况发生了什么。
以下代码编译没有问题:
文件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<<; 行 - 如果没有它,在最后一行的 test1() 中会出现错误(使用 gcc 4.5):

test_oper.cpp||在函数 'void test1()' 中:|
test_oper.cpp|22|错误:在 '((std::basic_ostream*)std::operator<<' 中没有匹配的运算符

编译器不应该通过自适应限定查找类型为 VecMat::MatrixD 的参数来找到运算符自身吗?
然而,当我添加一个新的类并将其自己的 operator<< 添加到 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

如果我从两个原始文件中的任何一个中包含“test_other.hpp”,那么.cpp文件将无法编译,出现与上述相同的错误,仅在test2()的最后一行。

test_oper.cpp||在函数'void Main::test2()':| test_oper.cpp|29|错误:没有匹配'operator<<' in '((std::basic_ostream*)std::operator<<

如果我将放入不同的命名空间(VecMat或新的命名空间),它可以正常编译。这是否意味着编译器首先查找Main,在那里找到一个operator<<(用于Foo),因此停止搜索并抱怨找到了错误的运算符?再次说,我本以为它会首先查找VecMat,因为参数的类型是VecMat :: MatrixD?
我希望能够解释发生了什么,并推荐以最干净的方式解决它。
非常感谢。 Michal

PS: 我也在其他地方发布了这个问题,那里建议我(http://www.cplusplus.com/forum/general/47766/#msg259246)在Main命名空间中添加using VecMat::operator<<;这行代码。这解决了问题 - 但我仍然想知道为什么需要这些代码以及是否这是最佳/推荐的解决方案。

1个回答

3

typedef不会引入新的类型。所以VecMat::MatrixD不是一个新的类型,它是boost::numeric::ublas::matrix<double>的别名,因此与ADL相关的命名空间是boost::numeric::ublas::matrix<double>的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接