4

下面的例子编译得很好,但我不知道如何分离 operator<<() 的声明和定义是这种特殊情况。

每次我尝试拆分定义时,朋友都会造成麻烦,而 gcc 抱怨 operator<<() 定义必须只采用一个参数。

#include <iostream>
template <typename T>
class Test {
    public:
        Test(const T& value) : value_(value) {}

        template <typename STREAM>
        friend STREAM& operator<<(STREAM& os, const Test<T>& rhs) {
            os << rhs.value_;
            return os;
        }
    private:
        T value_;
};

int main() {
    std::cout << Test<int>(5) << std::endl;
}

Operator<<() 应该有一个免费的第一个参数来处理不同类型的输出流(std::cout、std::wcout 或 boost::asio::ip::tcp::iostream)。第二个参数应该绑定到周围类的特殊版本。

Test<int> x;
some_other_class y;

std::cout << x; // works
boost::asio::ip::tcp::iostream << x; // works

std::cout << y; // doesn't work
boost::asio::ip::tcp::iostream << y; // works

除此之外,使用非成员函数并不等同于拆分定义和声明,因为非成员函数无法访问类的私有属性。

4

5 回答 5

4

最简单的可能是让所有这些模板运算符成为朋友:

#include <iostream>
template <typename T>
class Test
{
    public:
        Test(const T& value) : value_(value) {}

        template <typename STREAM, typename U>
        friend STREAM& operator<<(STREAM& os, const Test<U>& rhs);

    private:
        T value_;
};

template <typename STREAM, typename T>
STREAM& operator<<( STREAM& os, const Test<T>& rhs )
{
    os << rhs.value_;
    return os;
}
于 2010-05-12T15:17:57.330 回答
1

它不应该在类之外定义吗?

template <typename T>
class Test 
{  
    ...
    template <typename STREAM>
    friend STREAM& operator<<(STREAM& os, const Test<T>& rhs);
};

template <typename STREAM, typename T> 
STREAM& operator<<(STREAM& os, const Test<T>& rhs) 
{
    os << rhs.value_;
    return os;
}
于 2010-05-12T15:05:35.997 回答
1

我能达到的最接近的是

#include <iostream>

template <typename T>
class Test;

template <typename STREAM, typename T>
STREAM& operator<<(STREAM& os, const Test<T>& rhs);

template <typename T>
class Test {
public:
    Test(const T& value) : value_(value) {}

    template <typename STREAM, typename U>
    friend STREAM& operator<< (STREAM& os, const Test<U>& rhs);

private:
    T value_;
};

template <typename STREAM, typename T>
STREAM& operator<<(STREAM& os, const Test<T>& rhs) {
    os << rhs.value_;
    return os;
}

int main() {
    std::cout << Test<int>(5) << std::endl;
}

它将所有 operator<< 声明为朋友,而不是仅由 T 参数化的一个。问题是不可能部分专门化函数。一个人会喜欢使用

template <typename STREAM>
friend STREAM& operator<< <STREAM, T> (STREAM& os, const Test<T>& rhs);

但这不是有效的语法。(好吧,部分专业化不能声明为朋友)

于 2010-05-12T15:19:20.383 回答
0

问题是,在您提供的代码中,朋友是一个模板化函数,仅在第一个参数类型上参数化。也就是说,对于类模板的每个实例化类型 T(调用它mytype),您正在声明一个自由模板函数:

template <typename STREAM>
STREAM& operator<<( STREAM& os, Test<mytype> const & x );

重要的一点是with type argumentTest<mytype>的特定实例化。Testmytype

如果你真的想声明一个在流类型和模板的实例化类型中都被模板化的友元函数Test,你必须用两个参数声明一个友元。

另一方面,我建议您不要operator<<对流类型进行参数化,同时在类大括号内定义它,因为它有一些优势(名称查找规则略有不同)。

于 2010-05-12T16:00:14.930 回答
0

对于 Test 类的每个实例化类型 T,一个模板函数 operator<<() 被公开,它可以对不同类型的流进行操作。operator<<() 函数有一个自由的第一个参数,但有一个固定的第二个参数。

例子:

Test<int> x;
some_other_class y;

std::cout << x; // works
boost::asio::ip::tcp::iostream << x; // works

std::cout << y; // doesn't work
boost::asio::ip::tcp::iostream << y; // works

这就是 Test 类应该工作的方式。

于 2010-05-12T16:21:57.417 回答