代码之家  ›  专栏  ›  技术社区  ›  sancho.s ReinstateMonicaCellio

获取嵌套的类STL容器中的元素总数

  •  1
  • sancho.s ReinstateMonicaCellio  · 技术社区  · 5 年前

    1. 每层可以是任何类型的容器。

    2. 级别的数量不是预先给定的。

    here ):

    template <typename T>
    size_t get_total_size(const T & var)
    {
        if ( is_container<typeof(var)>::value ) {  // From https://stackoverflow.com/a/9407521/2707864
            typename T::const_iterator iter;
            size_t sumsize = 0;
            for ( iter = var.begin() ; iter!= var.end() ; iter++ ) {
                sumsize += get_total_size(*iter);
            }
            return sumsize;
        } else {
            return 1;
        }
    };
    

    问题是在使用它时(否则,写它就没有任何意义了!)不编译,因为实例化在“原子”级别得到一个没有迭代器的类型,例如,在这段代码中

    typedef vector<int> vint;
    typedef vector<vint> vvint;
    vvint vec_heap;
    for (int i=0; i < 12; i++) {
        vec_heap.push_back(vint(2, i));
    }
    cout << get_total_size(vec_heap) << endl;  // Instantiation leads to compilation errors 
    

    编辑 : 根据一条评论,它可以用c++17来完成。。。

    2 回复  |  直到 5 年前
        1
  •  2
  •   sancho.s ReinstateMonicaCellio    5 年前

    if constexpr :

    template <typename T>
    size_t get_total_size(const T& var)
    {
        if constexpr (is_container<T>::value) {
            return std::accumulate(var.begin(),
                                   var.end(),
                                   0u,
                                   [](int acc, const auto& e){ return acc + get_total_size(e); });
        } else {
            return 1u;
        }
    };
    

    在此之前,可以使用重载和SFINAE:

    // this will be called when T is not a container (it is the "atomic" type)
    template <typename T, std::enable_if_t<!is_container<T>::value, int> = 0>
    size_t get_total_size(const T& var)
    {
        return 1u;
    };
    // this will be called for all container types, except for maps
    template <typename T, std::enable_if_t<is_container<T>::value, int> = 0>
    size_t get_total_size(const T& var)
    {
        return std::accumulate(var.begin(),
                               var.end(),
                               0u,
                               [](int acc, const auto& e){ return acc + get_total_size(e); });
    };
    // this will be called for maps
    template <typename Key, typename T>
    size_t get_total_size(const std::map<Key, T> & var)
    {
        return std::accumulate(var.begin(),
                               var.end(),
                               0u,
                               [](int acc, const auto& e){ return acc + get_total_size_sfinae(e.second); });
    }
    
        2
  •  1
  •   NathanOliver    5 年前

    如果你不能使用C++ 17,或者只想打开你的函数使用什么标准,那么你可以切换到使用两个重载和使用 SFINAE 确定何时调用每个重载。使用

    // this will be called when T is not a container (it is the "atomic" type)
    template <typename T, typename std::enable_if<!is_container<T>::value, bool>::type = true>
    size_t get_total_size(const T & var)
    {
        return 1;
    }
    
    // forward declare of pair function for associative containers
    template <typename T, typename U>
    size_t get_total_size(const std::pair<T, U> & var);
    
    // this will be called for all container types
    template <typename T, typename std::enable_if<is_container<T>::value, bool>::type = true>
    size_t get_total_size(const T & var)
    {
        size_t sumsize = 0;
        for ( auto iter = var.begin() ; iter != var.end() ; ++iter ) {
            sumsize += get_total_size(*iter);
        }
        return sumsize;
    }
    
    // this will be called for pair to handle associative containers
    template <typename T, typename U>
    size_t get_total_size(const std::pair<T, U> & var)
    {
        return get_total_size(var.first) + get_total_size(var.second);
    }
    

    这将从C++ 11上运行,在上面你可以看到 live example