Home > OS >  Trying to print n-dimensional arrays in cpp
Trying to print n-dimensional arrays in cpp

Time:12-23

I am trying to print n dimensional arrays using a single function, which calls itself recursively if the parameter we are trying to print is a vector. Otherwise, the character should simply be printed. I've used templates to pass vectors i.e., vector<T> where T could be int, float, or another vector itself.

I've used two helper functions to check if the passed argument is a vector or not.

I am getting the following error message:

no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and '__gnu_cxx::__alloc_traits<std::allocator<std::vector<int> >, std::vector<int> >::value_type' {aka 'std::vector<int>'})

and

no matching function for call to '[print](https://www.stackoverflow.com/)(__gnu_cxx::__alloc_traits<std::allocator<int>, int>::value_type&)'

and

template constraint failure for 'template<class _Os, class _Tp>  requires (__derived_from_ios_base<_Os>) && requires(_Os& __os, const _Tp& __t) {__os << __t;} using __rvalue_stream_insertion_t = _Os&&'

Function to check if it is vector or not:

template<class T>
bool is_vector(const std::vector<T>& x) {return true;}

template<class T>
bool is_vector(const T& x) {return false;}

And the print function:

template <class T>
void print(vector<T> vect)
{
    if (!(is_vector(vect))) return;
    cout << "[ ";
    for( auto i = 0; i < vect.size(); i  )
    {
        if (is_vector(vect[i]))
        {
            print(vect[i]); // recursive call if vect[i] is also a vector.
        }
        else
        {
            cout << vect[i] << ' ';
        }
    }    
    cout << ']';
}

ALSO, I want to use this for vectors and not arrays.

CodePudding user response:

Please do not use using namespace std; in generic code or non-local scope.

The code does not compile because the compiler has to instantiate both branches even if it can deduce that one will never be taken. Since there is no overload for cout << vect[i] when vect[i] itself is a vector, the compilation fails.

You could use a if constexpr but you would need a compile-time check which is_vector isn't and marking them constexpr won't help here.

Instead, I would suggest a simpler variant using overloaded << which plays nicely with all types that can already be printed and thus removing the need for if.

print is then just a wrapper around this operator.

All functions also use const T& to avoid excessive copies.


#include <iostream>
#include <vector>

template <class T>
std::ostream& operator<<(std::ostream& o, const std::vector<T>& vec) {
    o << '[';
    for (std::size_t i = 0; i < vec.size();   i)
        o << (i != 0 ? " " : "") << vec[i];
    o << ']';
    return o;
}

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

int main() {
    std::vector<std::vector<int>> x{{1, 2, 3}, {4, 5, 6}};

    print(x);
}

Output:

[[1 2 3] [4 5 6]]

CodePudding user response:

All of a template specialization must be valid code. The only way around this is using something like if constexpr.

You could use concepts (or SFINAE pre C 20) to split the function into multiple overloads though; this is imho more readable than using if constexpr:


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

template<class T>
struct IsVectorHelper<std::vector<T>> : std::true_type
{};

template<class T>
concept IsVector = IsVectorHelper<T>::value;

template<class T>
concept IsNoVector = !IsVectorHelper<T>::value;

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

template<IsVector T>
void print(T const& vect)
{
    std::cout << "[ ";
    for (auto i = 0; i < vect.size(); i  )
    {
        print(vect[i]);
        std::cout << ' ';
    }
    std::cout << ']';
}

int main()
{
    print(std::vector<std::vector<int>>{ {1, 2, 3}, { 4, 5, 6}});

    return 0;
}

output

[ [ 1 2 3 ] [ 4 5 6 ] ]

Alternative implementation using if constexpr

template<class T>
constexpr bool IsVector_v = IsVectorHelper<T>::value;

template<class T>
void print2(T const& value)
{
    if constexpr (IsVector_v<T>)
    {
        std::cout << "[ ";
        for (auto i = 0; i < value.size(); i  )
        {
            print2(value[i]);
            std::cout << ' ';
        }
        std::cout << ']';
    }
    else
    {
        std::cout << value;
    }
}
  • Related