繁体   English   中英

在C ++中递归地打印矢量的STL向量

[英]Print simply STL vectors of vectors recursively in C++

我使用了下面的代码,它适用于使用printContainer()打印一个简单的std :: vector。
我现在想用printContainerV2()为嵌套容器扩展它
我已经尝试使用模板来确定类型是否是stl容器,但它似乎不是这样做的方式。

#include <iostream>
#include <iterator>
#include <vector>

template <typename Iter, typename Cont>
bool isLast(Iter iter, const Cont& cont)
{
    return (iter != cont.end()) && (next(iter) == cont.end());
}


template <typename T>
struct is_cont {
    static const bool value = false;
};

template <typename T,typename Alloc>
struct is_cont<std::vector<T,Alloc> > {
    static const bool value = true;
};


template <typename T>
std::string printContainer(T const& container)
{
    std::string str = "{";
    for (auto it = std::begin(container); it != std::end(container); ++ it)
        if (isLast(it, container))
                str = str + std::to_string(*it) + "}";
        else
                str = str + std::to_string(*it) + ",";
    return str;
}
/*
template <typename T>
std::string printContainerV2(T const& container)
{
    std::string str = "{";
    for (auto it = std::begin(container); it != std::end(container); ++ it)
        if (isLast(it, container))
            if (is_cont<decltype(*it)>::value == true)
                str = str + printContainer(*it);
            else
                str = str + std::to_string(*it) + "}";
        else
            if (is_cont<decltype(*it))>::value == true)
                str = str + printContainer(*it);
            else
                str = str + std::to_string(*it) + ",";
    return str;
}
*/
int main()
{
    std::vector<int> A({2,3,6,8});
    std::vector<std::vector<int>> M(2,A);
    M[1][0] ++;

    std::cout << is_cont<decltype(A)>::value << std::endl;  // returns true !

    for (auto it = std::begin(M); it != std::end(M); ++ it)
    {
        std::cout << printContainer(*it) << std::endl; // works well std::vector<int>
        std::cout << is_cont<decltype(*it)>::value << std::endl; // return false :(
    }

    // Want to use this for printing a std::vector<std::vector<int>>
   //  std::cout << printContainerV2(M) << std::endl; // not working !

}

目前,如果代码仅适用于std :: vector类型和最多一个嵌套级别(std :: vector <std :: vector >>),则可以。 我不确定没有努力就可以通用......

添加#include <type_traits>头并更换PrintContainerV2与此:

template<typename T>
using if_not_cont = std::enable_if<!is_cont<T>::value>;

template<typename T>
using if_cont = std::enable_if<is_cont<T>::value>;

template <typename T, typename if_not_cont<T>::type* = nullptr>
std::string printContainerV2(T const& container)
{
    std::string str = "{";
    for (auto it = std::begin(container); it != std::end(container); ++ it)
        if (isLast(it, container))
                str = str + std::to_string(*it) + "}";
        else
                str = str + std::to_string(*it) + ",";
    return str;
}

template <typename T, typename if_cont<T>::type* = nullptr>
std::string printContainerV2(T const& container)
{
    std::string str = "{";
    for (auto it = std::begin(container); it != std::end(container); ++ it)
        if (isLast(it, container))
                str = str + printContainer(*it) + "}";
        else
                str = str + printContainer(*it) + ",";
    return str;
}

您的解决方案不起作用的原因在于:

        if (is_cont<decltype(*it)>::value == true)
            str = str + printContainer(*it);
        else
            str = str + std::to_string(*it) + "}"; // <====

即使您正在进行的检查是编译时静态 - 仍然会编译if两个分支。 编译器仍会尝试评估std::to_string(std::vector<T> )并抱怨该函数不存在。 我们需要做的是使用SFINAE:替换失败不是错误。

这是我们的容器print版本:

template <typename T>
std::enable_if_t<is_cont<T>::value, std::string>
print(const T& container)
{
    // mostly the same as your code from printContainer() here, except instead of
    // std::to_string(*it), call print(*it).

    std::string str = "{";
    for (auto it = std::begin(container); it != std::end(container); ++ it)
    {
        str += print(*it);

        if (isLast(it, container)) {
            str += '}';
        }
        else {
            str += ',';
        }
    }

    return str;
}

而非容器版本:

template <typename T>
std::enable_if_t<!is_cont<T>::value, std::string>
print(const T& value)
{
    return std::to_string(value);
}

这在逻辑上与您在printContainerV2()中执行的操作相同,但这样, else分支 - to_string() - 将不会针对实际容器版本进行编译。

我修改了你的代码,最后我有了解决方法:

#include <iostream>
#include <iterator>
#include <vector>
#include <string>

using namespace std;

template <class N>
struct is_vector { static const int value = 0; };

template <class N, class A>
struct is_vector<std::vector<N, A> > { static const int value = 1; };

struct container_true {};
struct container_false {};

template <typename T>
std::string print(T const& container);

template <typename T>
std::string printContainer(T const& container, container_true)
{
    std::string ret = "{";
    for (auto it = std::begin(container); it != std::end(container); ++it)
    {
        ret += "{";
        ret += print(*it);
        ret += "}";
    }

    ret += "}";
    return ret;
}


template <typename T>
std::string printContainer(T const& container, container_false)
{
    std::string ret;
    for (auto it = std::begin(container); it != std::end(container); ++it)
    {
        ret += to_string(*it) + ",";
    }
    return ret.erase(ret.size() - 1);;
}

template <typename T>
std::string print(T const& container)
{
    typename std::conditional<is_vector<T::value_type>::value, container_true, container_false>::type mys;
    return printContainer(container, mys);
}

int main()
{
    std::vector<int> A({ 2, 3, 6, 8 });
    std::vector<std::vector<int>> M(2, A);
    M[1][0]++;
    std::vector<std::vector<std::vector<int>>> Z(2,  M);


    std::cout << print(A) << std::endl;
    std::cout << print(M) << std::endl;
    std::cout << print(Z) << std::endl;
}

编辑:更短的解决方案:

#include <iostream>
#include <vector>
#include <string>

template <class N>
struct is_vector { static const int value = 0; };

template <class N, class A>
struct is_vector<std::vector<N, A> > { static const int value = 1; };

template <typename T>
std::enable_if_t< is_vector<typename T::value_type>::value, std::string>
printContainer(T const& container)
{
    std::string ret = "{";
    for (auto& a : container)
        ret += "{" + printContainer(a) + "}";
    return ret + '}';
}

template <typename T>
std::enable_if_t< !is_vector<typename T::value_type>::value, std::string>
printContainer(T const& container)
{
    std::string ret;
    for (auto& a : container)
        ret += std::to_string(a) + ",";
    return ret.erase(ret.size() - 1);;
}

int main()
{
    std::vector<int> A({ 2, 3, 6, 8 });
    std::cout << printContainer(A) << std::endl;
}

我认为我的解决方案是递归的。 我能够打印任何嵌套的矢量。

main.cpp中

#include "vector.h"

int main(){
    std::vector<std::vector<std::vector<int>>> e = {{{1,2,3},{4,5,6},{7,8,9}},{{9,8,7},{6,5,4},{3,2,1}}};
    std::cout << e << std::endl;
    return 0;
}

“vector.h”

#ifndef VECTOR_H
#define VECTOR_H

#include <vector>
#include <iostream>

template<typename T1>
std::ostream& operator<<(std::ostream& stream, std::vector<T1> r){
    if(r.size() == 0){
        return stream;
    }
    else{
        stream << "(";
        for(int i = 0; i < r.size(); i++){
            if(i < (r.size() - 1)){
                stream << r[i] << ", ";
            }
            else{
                stream << r[i] << ")";
            }
        }
    }
    return stream;
};

#endif

暂无
暂无

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

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