通用打印函数,它既可以处理列表也可以处理标量实体?

时间:2014-03-18 14:42:26

标签: c++ templates recursion pretty-print

我试图编写一个我需要打印时可以调用的函数。但是,在打印矢量或列表时,我需要它的行为略有不同。此外,矢量或列表可以包含另一个矢量或列表。

我的第一个方法是做这样的事情:

#include <iostream>
#include <list>
#include <vector>

using namespace std;

template <typename T>
void
print(const vector<T>& v) {
    cout << "[";
    bool isFirst = true;
    for (const T& e : v) {
        if (isFirst) isFirst = false;
        else cout << ",";
        print(e);
    }
    cout << "]";
}

template <typename T>
void
print(const list<T>& l) {
    cout << "[";
    bool isFirst = true;
    for (const T& e : l) {
        if (isFirst) isFirst = false;
        else cout << ",";
        print(e);
    }
    cout << "]";
}

template <typename T>
void
print(const T& v) {
    cout << v;
}

int
main(int argc, char** argv) {
    vector<int> v;
    print(v);
    return 0;
}

如您所见,打印矢量和列表有很多代码重复,但我不知道如何组合它们。在任何情况下,代码都不会编译,因为编译器试图将标量实体(例如int)的打印与print的第一个实现匹配,而不是最后一个实现:

g++ -std=c++11 test.cpp
test.cpp: In instantiation of ‘void print(const std::vector<T>&) [with T = int]’:
test.cpp:42:12:   required from here
test.cpp:15:16: error: no matching function for call to ‘print(const int&)’
         print(e);
                ^
test.cpp:15:16: note: candidate is:
test.cpp:9:1: note: template<class T> void print(const std::vector<T>&)
 print(const vector<T>& v) {
 ^
test.cpp:9:1: note:   template argument deduction/substitution failed:
test.cpp:15:16: note:   mismatched types ‘const std::vector<T>’ and ‘const int’
         print(e);
                ^

我知道怎么解决这个问题吗?

2 个答案:

答案 0 :(得分:4)

有许多简洁的解决方案,但是一个非常接近你的解决方案没有重复,没有任何太聪明且没有任何库函数的是以下

template <typename T>
void print_container(const T&);

template <typename T>
void print(const std::vector<T>& v) { print_container(v); }

template <typename T>
void print(const std::list<T>& l) { print_container(l); }

template <typename T>
void print(const T& e) { cout << e; }

template <typename T>
void print_container(const T& c) {
    cout << "[";
    bool isFirst = true;
    for (const auto& e : c) {
        if (isFirst) isFirst = false;
        else cout << ",";
        print(e);
    }
    cout << "]";
}

答案 1 :(得分:0)

也许您应该遵循for_each算法的模式。请点击链接以获取如何定义该算法的示例。 http://www.cplusplus.com/reference/algorithm/for_each/

如果您想要一台通用的打印机,那么您应该更喜欢使用迭代器作为算法的输入。然后它没有区别哪个容器提供它们,你的函数甚至可以指向C数组。更进一步,如果您希望它适用于用户定义的类型,那么用户定义的类型应该有重载的流操作符来支持它们。

看看这个,并考虑更多的选择。 http://www.cplusplus.com/reference/iterator/ostream_iterator/

我无法在评论中发布此内容,但这是另一个答案的简化版本,主要用于测试。它在http://www.compileonline.com/compile_cpp11_online.php

进行了测试

当然,您可能需要其他类型的专业化,例如双重或用户定义的类型。

#include <vector>
#include <list>
#include <iostream>

template <typename T>
void print_container(const T&);

template <typename T>
void print(const T& e) { std::cout << e; }

template <typename T>
void print_container(const T& c) {
    std::cout << "[";
    bool isFirst = true;
    for (const auto& e : c) {
        if (isFirst) isFirst = false;
        else std::cout << ",";
        print(e);
    }
    std::cout << "]";
}

int main()
{
    std::vector<int> v = {0, 1, 3, 5, 7, 9};
    std::list<int> l =  {0, 1, 3, 5, 7, 9};

    print_container(v); 
    print_container(l);
}