如何在C ++中生成任意嵌套的向量?

时间:2017-11-06 06:10:58

标签: c++ c++11 templates vector c++17

在C ++中,是否可以生成一个深度(维度)等于用户定义输入的嵌套向量?例如,如果用户输入值为2的整数,则程序可能会创建类型为vector< vector< vector<int> > >的对象。显然,有许多其他方法可以轻松地在C ++中实现类似的行为,但我纯粹感兴趣的是,是否可以实际生成任意嵌套的向量。最初,我认为这将是相当微不足道的,但我的实现都以相当奇怪的方式失败了。

#include<iostream>
#include<vector>

using namespace std;

template<typename A> void vec_print(vector<A> in){
    cout << "{";
    for(typename vector<A> :: iterator i = in.begin(); i != in.end(); ++i){
        cout << *i << ", ";
    }
    cout << "}" << endl;
}

template<typename B> void vec_print(vector< vector<B> > in){
    cout << "{";
    for(typename vector< vector<B> > :: iterator i = in.begin(); i != in.end(); ++i){
        vec_print(*i); cout << ", ";
    }
    cout << "}" << endl;
}

template<typename T> auto generate(unsigned int d){
    if(d == 0){
        vector<T> in;
        return in;
    }
    return generate< vector<T> >(d - 1);
}

int main(){
    unsigned int d = 0;
    cin >> d;
    vec_print(generate<int>(d));
    return 0;
}

最初,我认为这可能有用,但由于我对C ++编译器如何处理模板函数的理解,我对此非常怀疑。使用带有--std=c++11标志的g ++编译器,在崩溃之前,g ++编译器递归地发出错误,通知我函数返回类型推导仅在C ++ 17规范下可用。尝试使用--std=c++17标志编译此程序导致没有错误,但编译器只是崩溃。我怀疑编译器试图生成无限数量的,或者可能是2 ^ 31个模板函数,尽管我希望它能够通过生成无限模板函数的错误警告来处理它,而不是静默死亡。

2 个答案:

答案 0 :(得分:2)

标准设置了符合程序不应超过的嵌套模板实例化深度(1024)的限制。但是,实现不需要强制执行或诊断此限制或任何其他实现限制。它可能无法编译任何&#34;太大&#34;。

的程序

gcc和clang都可以使用标志来设置用户定义的模板实例化深度限制。要查看正在进行的操作,请使用

g++ -std-c++17 -ftemplate-depth-20 yourprogram.cpp >& gcc.log

并查看生成的日志文件的大小。然后将深度增加到21并再次执行。多做几次,然后将你的发现推断到-ftemplate-depth-1024

当然编译器崩溃是一个QoI问题,应该被认为是一个bug。无论如何,您的程序不符合要求,因为它超出了实施数量。

如果要处理任意数量维度的向量,则不能使用递归模板。您必须使用其他技术,这些技术需要在运行时而不是在编译时设置维度。

答案 1 :(得分:2)

struct element_t;

struct element_t {
  ~element_t() {}
  using element_p = std::shared_ptr<element_t>;
  using data_t = std::variant< std::vector<element_p>, int >;
  data_t data;
  element_t(element_t const&)=default;
  element_t(data_t in):data(std::move(in)) {}
  element_t()=default;
};

element_t::data_t generate( unsigned int x ) {
  if (x==0) return {unsigned{0}};
  auto ptr = std::make_shared<element_t>(generate(x-1));
  auto vec = std::vector<element_t::element_p>{ptr};
  element_t::data_t r(vec);
  return r;
}

测试代码:

void print( element_t::data_t const& in ) {
    std::visit(
        [](auto const& e)
        {
            if constexpr( std::is_same< decltype(e), int const& >{} ) {
                std::cout << e << "\n";
            } else {
                for (const auto& x:e) {
                    if (!x)
                    {
                        std::cout << "null\n";
                    }
                    else
                    {
                        std::cout << "nest\n";
                        print(x->data);
                        std::cout << "unnest\n";
                    }
                }
            }
        },
        in
    );
}
int main() {
    auto r = generate(10);
    print(r);
}

Live example