operator<<(ostream&, const BigUnsigned<I>&) 必须只有一个参数

Posted

技术标签:

【中文标题】operator<<(ostream&, const BigUnsigned<I>&) 必须只有一个参数【英文标题】:operator<<(ostream&, const BigUnsigned<I>&) must take exactly one argument 【发布时间】:2016-04-27 22:53:15 【问题描述】:

我试图将模板化类的模板化成员函数的声明和定义分开,但最终出现以下错误和警告。

template <typename I>
class BigUnsigned
    const size_t cell_size=sizeof(I);
    std::vector<I> _integers;
public:
    BigUnsigned();
    BigUnsigned(I);
    friend std::ostream& operator<<(std::ostream& out, const BigUnsigned& bu);
;

std::ostream& operator<<(std::ostream& out, const BigUnsigned& bu)
    for (auto integer : bu._integers)
        out<<integer<<std::endl;
    
    return out;

../hw06/bigunsigned.h:13:77:警告:朋友声明 'std::ostream& 运算符)../hw06/bigunsigned.h:16:51: 错误:在没有参数的情况下无效使用模板名称“BigUnsigned” 列出 std::ostream& 运算符

当我像这样加入声明和定义时,一切都编译得很好。

template <typename I>
class BigUnsigned
    const size_t cell_size=sizeof(I);
    std::vector<I> _integers;
public:
    BigUnsigned();
    BigUnsigned(I);
    friend std::ostream& operator<<(std::ostream& out, const BigUnsigned& bu)
        for (auto integer : bu._integers)
            out<<integer<<std::endl;
        
        return out;
    
;

目的是将成员变量_整数打印到cout。可能是什么问题?

P.S.:使用 this question 我免费提供了该功能,但没有帮助。

【问题讨论】:

FWIW,对于 me 来说,BigUnsigned 成为一个容器似乎有点出人意料。不过,请注意这一点。 @erip,你为什么认为BigUnsigned在这里是一个容器? operator&lt;&lt; 是一个格式化操作符。它与容器无关。 @JanHudec 不,但是将数据存储在std::vector 与容器有关。 @JanHudec BigUnsigned&lt;std::string&gt; bu"Hello, World"; /* oops, not really a big unsigned after all */ @erip,如果没有任意大小的东西并且某物是向量,您将无法获得任意精度。至于使用std::string作为参数,想必没有显示的方法要求参数是数字类型。 【参考方案1】:

对the answer by NathanOliver的改进。

对于另一个答案,函数模板的所有实例化都是类模板的所有实例化的friends。

operator&lt;&lt; &lt;int&gt;friendBigUnsigned&lt;int&gt; 以及 BigUnsigned&lt;double&gt;

operator&lt;&lt; &lt;double&gt;friendBigUnsigned&lt;double&gt; 以及 BigUnsigned&lt;FooBar&gt;

您可以稍微更改声明,以便

operator&lt;&lt; &lt;int&gt;friendBigUnsigned&lt;int&gt; 但不是 BigUnsigned&lt;double&gt;

operator&lt;&lt; &lt;double&gt;friendBigUnsigned&lt;double&gt; 但不是 BigUnsigned&lt;FooBar&gt;

// Forward declaration of the class template.
template <typename I> class BigUnsigned;

// Forward declaration of the function template
template <typename I>
std::ostream& operator<<(std::ostream& out, const BigUnsigned<I>& bu);

// Change the friend-ship declaration in the class template.
template <typename I>
class BigUnsigned
    const size_t cell_size=sizeof(I);
    std::vector<I> _integers;
public:
    BigUnsigned();
    BigUnsigned(I);

    // Grant friend-ship only to a specific instantiation of the
    // function template.
    friend std::ostream& operator<< <I>(std::ostream& out, const BigUnsigned<I>& bu);
;

【讨论】:

您介意添加内联定义朋友函数的可能性吗? @phresnel,你的意思是在BigUnsigned的定义中定义它吗? 是的,当然,有时这会让事情更易于维护。 @phresnel,你不能按照我的建议在类模板定义中实现operator&lt;&lt; 函数。它必须在外部实施。 我刚刚意识到您也在定义一个免费的模板函数。你当然是对的;我将添加我的解决方案作为另一个答案。【参考方案2】:

添加第三个变体来稍微提高可读性,就是在类中定义友元函数:

#include <iostream>

template <typename T>
class Foo 
    int test = 42;

    // Note: 'Foo' inside the class body is basically a shortcut for 'Foo<T>'
    // Below line is identical to: friend std::ostream& operator<< (std::ostream &os, Foo<T> const &foo)
    friend std::ostream& operator<< (std::ostream &os, Foo const &foo) 
        return os << foo.test;
    
;


int main () 
    Foo<int> foo;
    std::cout << foo << '\n';

【讨论】:

【参考方案3】:

BigUnsigned 是一个模板类型所以

std::ostream& operator<<(std::ostream& out, const BigUnsigned& bu)

由于没有BigUnsigned,因此无法工作。您需要将朋友功能设为模板,以便您可以获取不同类型的BigUnsigned&lt;some_type&gt;s。

template <typename I>
class BigUnsigned
    const size_t cell_size=sizeof(I);
    std::vector<I> _integers;
public:
    BigUnsigned();
    BigUnsigned(I);
    template<typename T>
    friend std::ostream& operator<<(std::ostream& out, const BigUnsigned<T>& bu);
;

template<typename T>
std::ostream& operator<<(std::ostream& out, const BigUnsigned<T>& bu)
    for (auto integer : bu._integers)
        out<<integer<<std::endl;
    
    return out;

第二个示例有效的原因是,由于它是在类内部声明的,因此它使用该类使用的模板类型。

【讨论】:

@Slazer,实际上,你想让template &lt;typename T&gt; std::ostream&amp; operator&lt;&lt;(std::ostream&amp;, const BigUnsigned&lt;T&gt;&amp;)成为BigUnsigned&lt;I&gt;的朋友,因为IT不相关,所以你不想在朋友声明前加上typename。您只需要在类外定义前加上前缀;见 R Sahu 的回答。

以上是关于operator<<(ostream&, const BigUnsigned<I>&) 必须只有一个参数的主要内容,如果未能解决你的问题,请参考以下文章

错误:'operator<<' 不匹配(操作数类型为'std::ostream' aka'std::basic_ostream<char>' 和'std::_List_iter

operator<<(ostream&, const BigUnsigned<I>&) 必须只有一个参数

spdlog 错误:“不知道如何格式化类型,包括 fmt/ostream.h 如果它提供了应该使用的 operator<<”

OpenCV 2.1:ostream operator<< for cv::Mat 在哪里?

流运算符的重载

STL基础--流