如何在模板类中拆分模板友元函数的定义?

发布于 2024-09-02 00:09:19 字数 1015 浏览 6 评论 0原文

下面的示例编译良好,但我无法弄清楚如何在这种特殊情况下分离运算符<<() 的声明和定义。

每次我尝试拆分定义时,朋友都会造成麻烦,并且 gcc 抱怨运算符 <<() 定义必须恰好采用一个参数。

#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

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

The following example compiles fine but I can't figure out how to separate declaration and definition of operator<<() is this particular case.

Every time I try to split the definition friend is causing trouble and gcc complains the operator<<() definition must take exactly one argument.

#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<<() is supposed to have a free first parameter to work with different kind of output streams (std::cout, std::wcout or boost::asio::ip::tcp::iostream). The second parameter should be bound to a specialized version of the surrounding class.

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

Besides that using a non-member-function isn't equivalent to splitting the definition and declaration because non-member-functions can't access private attributes the the class.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

樱花细雨 2024-09-09 00:09:20

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

#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;
}

The easiest is probably to make all these template operators friends:

#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;
}
眉目亦如画i 2024-09-09 00:09:20

我能实现的最接近的是

#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;
}

声明所有运算符<<作为朋友,而不仅仅是由 T 参数化的朋友。问题是不可能部分专门化函数。有人会喜欢使用,

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

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

The nearest I can achieve is

#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;
}

which declares all operator<< as friend instead of only the one parametrized by T. The problem is that it isn't possible to partially specialize functions. One would have liked to use

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

but that isn't valid syntax. (Well, and partial specialization can't declared friend)

楠木可依 2024-09-09 00:09:20

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

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;
}

Shouldn't it be defined outside of the class ?

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;
}
风吹雪碎 2024-09-09 00:09:20

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

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

重要的一点是 Test是带有类型参数 mytypeTest 的特定实例。

如果您确实想声明一个在流类型和 Test 模板的实例化类型中模板化的友元函数,则必须声明带有两个参数的友元。

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

The problem is that in the code that you present the friend is a templated function parametrized only on the first argument type. That is, for each instantiating type T of the class template (call it mytype), you are declaring a free template function:

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

The important point there is that Test<mytype> is the particular instantiation of Test with type argument mytype.

If you really want to declare a friend function that is templated in both the stream type and the instantiating type of the Test template, you must declare a friend with two arguments.

On the other hand, I recommend that you do not parametrize operator<< on the stream type, and at the same time, that you define it inside the class braces as it has slight advantages (name lookup rules are slightly different).

何时共饮酒 2024-09-09 00:09:20

对于 Test 类的每个实例化类型 T,都会公开一个模板函数运算符<<(),它可以在不同类型的流上进行操作。 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

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

For each instantiated type T of class Test a template function operator<<() is exposed which can operate on different kind of streams. The operator<<() function has a free first parameter but a fixed second parameter.

example:

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

That's the way the Test class was supposed to work.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文