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

Get total number of elements in a nested STL-like container

我想编写一个 C++ 函数来计算通用嵌套类 STL 容器中 "atomic" 元素的总数,条件如下:

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

  2. 层数不是先验的

我编写了以下递归函数(使用 here 中的代码):

template <typename T>
size_t get_total_size(const T & var)
{
    if ( is_container<typeof(var)>::value ) {  // From 
        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;
    }
};

Compiling/linking 这可能有效。 问题是在使用它时(否则,编写它没有任何意义!)不编译,因为实例化在 "atomic" 级别达到没有迭代器的类型,例如,在此代码

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 来完成...... 我为objective写的递归函数是不是有点矫枉过正了?

对于 C++17,您可以使用 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); });
}

如果你不能使用 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

中看到