Home > Software design >  C template recursively print a vector of vector using template
C template recursively print a vector of vector using template

Time:03-31

#include <any>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
using namespace std;

template<class T>
struct is_vector : std::false_type {};
template<class T>
inline constexpr bool is_vector_v = is_vector<T>::value;

template <typename T>
string VectorToString(const vector<T> &vec)
{
    string res = "[";
    int n = vec.size();
    for (size_t i=0; i<n; i  ) {
        if constexpr(is_vector_v<T>) res  = VectorToString(vec[i]);
        else res  = std::to_string(vec[i]);
        if (i < n-1) res  = ", ";
    }
    res  = "]";
    return res;
}

int main( int argc, char** argv ) 
{        
    vector<int> a = {1,2,3};
    cout << VectorToString(a) << "\n";

    vector<vector<int>> b = {{1,2,3}, {4,5,6}, {7,8,9}};
    //cout << VectorToString(b);    

    vector<vector<vector<double>>> c = {{{1,2,3}, {4,5,6}}, {{7,8,9}}};
    //cout << VectorToString(c);    
    return 0;
}

I'm trying to make a print function that works with any vector type, like Python.

I wish to use template if possible, but not sure how. What should struct is_vector looks like to do this?

If a template solution is not possible, then I'd like to see any solution possible.

CodePudding user response:

What should struct is_vector looks like to do this?

It looks like what template partial specialization looks like

template<class T>
struct is_vector : std::false_type {};

template<class T, class Alloc>
struct is_vector<std::vector<T, Alloc>> : std::true_type {};

Demo

CodePudding user response:

One option is to mix templates and operator overloading as shown below. In particular, to overload operator<< for a std::vector. A very crude example is given below. It prints all the elements of a std::vector.

//this will be selected for 1D std::vector
template<typename T> 
std::ostream& operator<<(std::ostream &os, const std::vector<T> &vec)
{
    for(auto it = vec.begin(); it!=vec.end();   it)
    {
        os<< (*it)<<" ";
    }
    return os;
}
//for arbitrarily nested std::vector
template<typename T> 
std::ostream& operator<<(std::ostream &os, const std::vector<std::vector<T>> &vec)
{
    
    for(auto it = vec.begin(); it!=vec.end();   it)
    {
        os << *it;
    }
    
    return os;
}
int main()
{
    std::vector<int> vec1{1,2,3};
    std::cout<<vec1<<std::endl; //prints 1 2 3 
    
    std::vector<std::vector<int>> vec2 = {{1,2,3}, {4,5,6}, {7,8,9}}; //1 2 3 4 5 6 7 8 9
    std::cout<<vec2<<std::endl;
    
    std::vector<std::vector<std::vector<double>>> vec3{{{1,2,3}, {4,5,6}, {7,8,9}}, {{-1,-2,-3}, {-4,-5,-6}, {-10,-22,36}}, {{129,212,999}, {0,0,1}, {3,5,4}}};
    std::cout<<vec3<<std::endl;
    return 0;
}

The output of the above program is:

1 2 3
1 2 3 4 5 6 7 8 9 
1 2 3 4 5 6 7 8 9 -1 -2 -3 -4 -5 -6 -10 -22 36 129 212 999 0 0 1 3 5 4

Demo.

Another option would be to use fold expressions for the same.

  • Related