简体   繁体   English

如何以通用方式打印任何容器的内容?

[英]How could I print the contents of any container in a generic way?

I am trying to write a piece of code for fun using C++ templates.我正在尝试使用 C++ 模板编写一段有趣的代码。

#include <iostream>
#include <vector>

template <class Container>
std::ostream& operator<<(std::ostream& o, const Container& container)
{
    typename Container::const_iterator beg = container.begin();

    o << "["; // 1

    while(beg != container.end())
    {
        o << " " << *beg++; // 2
    }

    o << " ]"; // 3

    return o;
}

int main()
{
    std::vector<int> list;

    list.push_back(0);
    list.push_back(0);

    std::cout << list;

    return 0;
}

The above code doesn't compile :)上面的代码无法编译:)

At 1, 2, 3 the same error is produced : error C2593: 'operator <<' is ambiguous在 1、2、3 处产生相同的错误:错误 C2593: 'operator <<' is ambiguous

All what I am trying to do is overloading the << operator to work with any container.我要做的就是重载 << 运算符以使用任何容器。 Does that make sense ?那有意义吗 ? How would that be done If possible, if not why ?如果可能的话,那将如何做,如果不是,为什么?

EDIT :: Thanks for corrections :) 'sth' way is a good solution.编辑 :: 感谢您的更正:) 'sth' 方式是一个很好的解决方案。

I am just curious if this ambiguity -as Neil explained- would go away if we could use C++0x Concepts ?我只是好奇,如果我们可以使用 C++0x 概念,这种歧义 - 正如 Neil 解释的那样 - 会消失吗?

You can restrict your operator<< to only apply to templated containers by specifying that the Container template parameter is itself templated.您可以通过指定 Container 模板参数本身是模板化的,来限制您的 operator<< 仅适用于模板化容器。 Since the C++ std containers also have an allocator template parameter you also have to include this as a template parameter of Container.由于 C++ 标准容器也有一个分配器模板参数,因此您还必须将其作为 Container 的模板参数包含在内。

template
    < typename T
    , template<typename ELEM, typename ALLOC=std::allocator<ELEM> > class Container
    >
std::ostream& operator<< (std::ostream& o, const Container<T>& container)
{
    typename Container<T>::const_iterator beg = container.begin();

    o << "["; // 1

    while(beg != container.end())
    {
        o << " " << *beg++; // 2
    }

    o << " ]"; // 3

    return o;
}

int main()
{
    std::vector<int> list;

    list.push_back(0);
    list.push_back(0);

    std::cout << list;

    return 0;
}

Your newly defined operator<< does not only match containers, but also any other types like ints and strings.您新定义的operator<<不仅匹配容器,还匹配任何其他类型,如整数和字符串。 That's why the compiler complains about ambiguities when it needs to find the matching operator<< to output "[" .这就是为什么编译器在需要找到匹配的operator<<以输出"["时抱怨歧义的原因。

One way to work around this problem would be to rename your output function:解决此问题的一种方法是重命名您的输出函数:

template <class Container>
std::ostream& container_out(std::ostream& o, const Container &container) {
  // ...
}

You can then add simple wrappers to enable operator<< for all the containers you want to print:然后,您可以添加简单的包装器来为要打印的所有容器启用operator<<

template<typename T>
std::ostream& operator<<(std::ostream& o, const std::vector<T> &container) {
  return container_out(o, container);
}

template<typename T>
std::ostream& operator<<(std::ostream& o, const std::map<T> &container) {
  return container_out(o, container);
}

What is the error?错误是什么? I saw one, you need a typename:我看到了一个,你需要一个类型名:

typename Container::iterator beg = container.begin();

What happens here is that the compiler doesn't know anything about Container when it is first reading it.这里发生的是编译器在第一次读取 Container 时对它一无所知。 So we have to give it a little help and tell it that iterator will be a type(syntactically it could be any valid name at class scope, so a function, variable,...).所以我们必须给它一点帮助,告诉它迭代器将是一个类型(从语法上讲,它可以是类范围内的任何有效名称,所以是函数、变量……)。 When writing a template method, any type that depends on the template type must specify that it is a type with the keyword typename .在编写模板方法时,任何依赖于模板类型的类型都必须指定它是带有关键字typename的类型。

Your operator introduces its own ambiguity - it could itself be used for printing the things it is trying to print.您的操作员引入了自己的歧义 - 它本身可以用于打印它试图打印的东西。 My advice:我的建议:

  • use a named function, not an operatr使用命名函数,而不是操作符
  • pass the container by const reference (this is nothing to do with the problem, however)通过 const 引用传递容器(但这与问题无关)

Ok, now your template it causing confusion.好的,现在你的模板引起了混乱。 The compiler can't decide between your operator and the one that you would expect.编译器无法在您的运算符和您期望的运算符之间做出决定。

Maybe not as generic as what you are posting (you need to pass the type contained), and also leaves an extra separator at the end, but you can use the STL for this:也许不像您发布的那样通用(您需要传递包含的类型),并且最后还会留下一个额外的分隔符,但是您可以为此使用 STL:

std::vector<int> v;
v.push_back( 10 );
v.push_back( 20 );

std::cout << "[";
std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, " " ) );
std::cout << "]";

Will output:将输出:

[10 20 ] [10 20]

Note that the extra separator is at the end of the sequence and that there is no initial space between the [ and the first element.请注意,额外的分隔符位于序列的末尾,并且 [ 和第一个元素之间没有初始空格。

http://blog.csdn.net/cqdjyy01234/article/details/19234329 may be a good solution. http://blog.csdn.net/cqdjyy01234/article/details/19234329可能是一个很好的解决方案。 It works for STL containers and the C-style array.它适用于 STL 容器和 C 风格的数组。

You can use constexpr to check Datatype of containers like Stacks,Queues for different printing mechanism and add generic method called PrintContainer check the below code.您可以使用constexpr检查堆栈、队列等容器的数据类型以了解不同的打印机制,并添加名为PrintContainer的通用方法检查以下代码。

First check datatype for Stack,Queue,Map etc.首先检查 Stack、Queue、Map 等的数据类型。

// Template for Checking Map.
template <class T>
struct is_map
{
    static constexpr bool value = false;
};

template <class Key, class Value>
struct is_map<std::map<Key, Value>>
{
    static constexpr bool value = true;
};

// Template for Checking Stack.
template <class T>
struct is_stack
{
    static constexpr bool value = false;
};

template <class T>
struct is_stack<std::stack<T>>
{
    static constexpr bool value = true;
};

// Template for Checking Queue.
template <class T>
struct is_queue
{
    static constexpr bool value = false;
};

template <class T>
struct is_queue<std::queue<T>>
{
    static constexpr bool value = true;
};

Then include General method for Printing Container like this.然后包括像这样打印容器的通用方法。

template <typename T>
void PrintContainer(T container, bool showSize = false)
{
    if (showSize)
        std::cout << "Size: " << container.size() << std::endl;
    // Container for Map.
    if constexpr (is_map<T>::value)
    {
        for (const auto &[k, v] : container)
        {
            std::cout << k << "\t" << v << std::endl;
        }
    }
    // Container for Stack & Queue.
    else if constexpr (is_stack<T>::value || is_queue<T>::value)
    {
        while (!container.empty())
        {
            if constexpr (is_stack<T>::value)
                std::cout << container.top() << "\t";
            else if constexpr (is_queue<T>::value)
                std::cout << container.front() << "\t";
            container.pop();
        }
    }
    // General Container like list,set etc.
    else
    {
        for (const auto &data : container)
        {
            if constexpr (!is_map<T>::value)
                std::cout << data << "\t";
        }
    }
    std::cout << std::endl;
}

Then call it from Main method like this.然后像这样从 Main 方法调用它。

int main()
{
    //Defining containers.
    std::list<int> iList({10, 20, 30, 40, 50});
    std::map<string, string> sMap{
        {"Abdul", "Java"},
        {"Mohammed", "C++"},
        {"Ahmet", "Python"}};
    std::set<int> iSet({10, 20, 30, 40, 50, 10, 30});
    std::array<int, 5> iArray({11, 22, 33, 44, 55});
    std::stack<float> fStack({1.5, 2.5, 3.5, 4.5});
    std::queue<float> fQueue({11.5, 22.5, 33.5, 44.5});

    //Printing data of containers.
    PrintContainer(iList);
    PrintContainer(sMap);
    PrintContainer(iSet);
    PrintContainer(iArray);
    PrintContainer(fStack);
    PrintContainer(fQueue);

    return 0;
}

Output:输出:

10      20      30      40      50
Abdul   Java
Ahmet   Python
Mohammed        C++

10      20      30      40      50
11      22      33      44      55
4.5     3.5     2.5     1.5
11.5    22.5    33.5    44.5

Full Source Code - PrintContainer.cpp 完整源代码 - PrintContainer.cpp

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM