【问题标题】:Template function taking a std::vector or std::array模板函数采用 std::vector 或 std::array
【发布时间】:2012-12-08 14:28:02
【问题描述】:

我有一个函数,目前接受 2 个可以包含任何普通旧数据的向量 ...

template <class T>
void addData(const vector<T>& yData, vector<T> xData)
{ .. }

问题:

  • 考虑到这些容器采用不同数量的模板参数,是否可以将其修改为采用两个std::array 或两个std::vector,甚至是两者的组合?

【问题讨论】:

  • 如果不是std::array&lt;&gt;的讨厌的非类型模板参数,它会。
  • 需要用到哪些成员函数?
  • 您真的只需要接受std::vector&lt;&gt;s 或std::array&lt;&gt;s,还是真的想接受来自任何容器任何范围的值 /i>?您可能应该使用迭代器!

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


【解决方案1】:

当然,这只是创建合适的类型特征的问题。该示例仅使用带有一个参数的函数f(),但扩展为采用任意数量的参数是微不足道的。

#include <array>
#include <vector>
#include <deque>
#include <utility>
#include <cstddef>

template <typename T>
struct is_array_or_vector {
    enum { value = false };
};

template <typename T, typename A>
struct is_array_or_vector<std::vector<T, A>> {
    enum { value = true };
};

template <typename T, std::size_t N>
struct is_array_or_vector<std::array<T, N>> {
    enum { value = true };
};

template <typename T>
typename std::enable_if<is_array_or_vector<T>::value>::type
f(T const&)
{
}

int main()
{
    f(std::vector<int>());    // OK
    f(std::array<int, 17>()); // OK
    f(std::deque<int>());     // ERROR
}

【讨论】:

    【解决方案2】:

    另一种解决方案:

    #include <iostream>
    #include <vector>
    #include <array>
    
    using std::vector;
    using std::array;
    
    template <typename Container>
    struct container_helper; // undefined
    
    template <typename T>
    struct container_helper<vector<T>>
    {    
        explicit container_helper(vector<T>& data)
        : _data(data)
        {}
    
        T* get_data()
        { return &_data[0]; }
    
        size_t get_size()
        { return _data.size(); }
    
    private:
        vector<T>& _data;
    };
    
    template <typename T, size_t N>
    struct container_helper<array<T,N>>
    {
        explicit container_helper(array<T,N>& data)
        : _data(data)
        {}
    
        T* get_data()
        { return &_data[0]; }
    
        size_t get_size()
        { return N; }
    
    private:
        array<T,N>& _data;
    };
    
    
    template <typename Container1, typename Container2>
    void add_data(Container1& c1, Container2& c2)
    {
        container_helper<Container1> c1_helper(c1);
        container_helper<Container2> c2_helper(c2);
    
        /* do whatever you want with the containers */
        std::cout << "c1 size " << c1_helper.get_size() << std::endl;
        std::cout << "c2 size " << c2_helper.get_size() << std::endl;
    }
    
    
    int main()
    {
        vector<int > v_ints(3);
        array<int, 2> a_ints;
    
        add_data(v_ints, a_ints);
    }
    

    【讨论】:

    • std::vectorstd::array 公共接口足够兼容,您不需要任何适配器类(在这种情况下)。
    • @BenVoigt 当然可以,但是这样可以轻松扩展以支持其他容器类型。
    • @Gigi:你所做的只是创建临时迭代器。
    • @Gigi:首选方法是松散函数,没有任何包装类型。例如std::beginstd::end
    【解决方案3】:

    为什么不直接使用它,它适用于任何使用随机访问迭代器的容器,包括普通的旧数组。如果您可以使用迭代而不是索引,那么您也可以取消随机访问要求。

    template <typename Cnt1, typename Cnt2>
    void addData(const Cnt1& yData, Cnt2 xData) // is pass-by-value intended?
    {
        using std::begin;
        using std::end;
        typedef decltype(*begin(yData)) T;
        const auto sizeY = end(yData) - begin(yData);
        const auto sizeX = end(xData) - begin(xData);
        // ...
    }
    

    C++03 版本(不支持普通旧数组):

    template <typename Cnt1, typename Cnt2>
    void addData(const Cnt1& yData, Cnt2 xData) // is pass-by-value intended?
    {
        typedef Cnt1::value_type T;
        const size_t sizeY = yData.end() - yData.begin();
        const size_t sizeX = xData.end() - xData.begin();
        // ...
    }
    

    【讨论】:

    • 这里不需要std::distance 吗?如果不是,那是为了什么?
    • std::distance 只需要输入迭代器,而迭代器减法需要随机访问迭代器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-28
    • 2016-02-12
    • 2020-05-21
    • 1970-01-01
    • 1970-01-01
    • 2021-05-26
    相关资源
    最近更新 更多