【问题标题】:output a collection of collections using templated operator<<使用模板化操作符<< 输出集合的集合
【发布时间】:2019-04-18 14:08:48
【问题描述】:

我想通过操作符调用外部集合一次来输出集合的集合(在这种情况下为向量的向量)

当我从 operator&lt;&lt;() 函数中删除 ' ' 时它可以工作,但我希望每行的每个输出元素之间都有一个空格。 我尝试用" "(也包括字符串头文件)替换' ',但得到了同样的错误。

有没有办法解决这个问题?

#include <iostream>
#include <vector>

using namespace std;

vector<vector<bool>> lookup(10, vector<bool>(10, true));

template <typename T>
ostream& operator<< (ostream& out, const T& collection)
{
    for (const auto& elem : collection)
        out << elem << ' ';
    return out << endl;
}

int main()
{
    cout << lookup << endl;
}

我收到以下错误:

1>------ Build started: Project: test, Configuration: Debug Win32 ------
1>test.cpp
1>c:\users\user\source\repos\codechef\practice\beginner\test\test\test.cpp(16): error C2593: 'operator <<' is ambiguous
1>c:\users\user\source\repos\codechef\practice\beginner\test\test\test.cpp(13): note: could be 'std::ostream &operator <<<char>(std::ostream &,const T &)'
1>        with
1>        [
1>            T=char
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\ostream(921): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,_Elem)'
1>        with
1>        [
1>            _Elem=char
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\ostream(834): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char)'
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\ostream(749): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char)'
1>c:\users\user\source\repos\codechef\practice\beginner\test\test\test.cpp(16): note: while trying to match the argument list '(std::ostream, char)'
1>c:\users\user\source\repos\codechef\practice\beginner\test\test\test.cpp(22): note: see reference to function template instantiation 'std::ostream &operator <<<std::vector<std::vector<bool,std::allocator<_Ty>>,std::allocator<std::vector<_Ty,std::allocator<_Ty>>>>>(std::ostream &,const T &)' being compiled
1>        with
1>        [
1>            _Ty=bool,
1>            T=std::vector<std::vector<bool,std::allocator<bool>>,std::allocator<std::vector<bool,std::allocator<bool>>>>
1>        ]
1>Done building project "test.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

【问题讨论】:

    标签: c++ templates vector output


    【解决方案1】:

    问题是模板中的T 不限于特定类型或类型范围。编译器可以用它想要的任何类型替换它。

    当您编写out &lt;&lt; ' '; 时,编译器会查找函数ostream&amp; operator&lt;&lt; (ostream&amp; out, const char&amp; collection) 并找到两个这样的函数。其中一个来自标准库,另一个是您的函数。 编译器无法决定它应该使用哪个版本,所以它只是停止编译。

    要解决此问题,您需要限制您的模板,使其不接受您不需要的类型。 一种方法是制作一个仅接受 vector 的模板:

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    vector<vector<bool>> lookup(10, vector<bool>(10, true));
    
    template <typename T>
    ostream& operator<< (ostream& out, const vector<T>& collection)
    {
        for (const auto& elem : collection)
            out << elem << ' ';
        return out << endl;
    }
    
    int main()
    {
        cout << lookup << endl;
    }
    

    如果您需要为更多类型的容器定义此函数,而不是多次复制它,您可以创建一个接受所有类型但它没有与标准库冲突的名称的模板。然后你可以创建几个简单的operator&lt;&lt; 实例,它们只调用你的通用函数。

    #include <iostream>
    #include <vector>
    #include <array>
    
    using namespace std;
    
    vector<vector<bool>> lookup(10, vector<bool>(10, true));
    
    template <typename T>
    ostream& printCollection (ostream& out, const T& collection)
    {
        for (const auto& elem : collection)
            out << elem << ' ';
        return out << endl;
    }
    
    template <typename T>
    ostream& operator<< (ostream& out, const vector<T>& collection)
    {
        return printCollection(out, collection);
    }
    
    template <typename T, size_t N>
    ostream& operator<< (ostream& out, const array<T, N>& collection)
    {
        return printCollection(out, collection);
    }
    
    int main()
    {
        cout << lookup << endl;
    }
    

    我认为甚至可以不为每种类型的容器单独定义功能。不过,它需要一些高级模板魔法。 您可以阅读此c++ template class; function with arbitrary container type, how to define it? 以了解更多信息。

    【讨论】:

    • 我更喜欢它是否适用于各种集合组合(如 array, 10>)。有没有办法让它拒绝字符集合(?)?
    • @ShreyasRagit 您可以阅读这个问题:stackoverflow.com/q/874298/3052438 但是我建议您宁愿定义接受其他类型的函数版本。当您尝试超出限制范围的内容时,仅限制某些类型会导致类似的错误。我将扩展我的答案以展示一些示例。
    • 谢谢!这是一个很好的解决方法。我对此有另一个疑问,所以我会在这里问。当我在答案的第一部分运行代码时,我得到了一些奇怪的缩进。第一行打印正常,但从第二到第十行,第一个元素之前有一个空格。我不知道为什么。你可以试试运行它吗?
    • @ShreyasRagit 这是由于您在向量的每个元素后添加空格造成的。对于简单的向量来说它工作得相对不错,但是当你尝试打印向量的向量时它会变得平淡,因为在打印每个向量 id 后都会增加额外的空间,而恰好在行的开头,因为函数以 endl 结尾。如果你想让所有东西都对齐,你必须发明一些更复杂的算法。
    猜你喜欢
    • 1970-01-01
    • 2017-02-17
    • 1970-01-01
    • 2015-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多