Могут ли не типовые аргументы шаблона выполняться на контейнерах stl? - PullRequest
3 голосов
/ 23 сентября 2019
template<typename T,int nSize>
T Sum(T (&parr)[nSize])
{
    T sum=0;
    for(int i = 0; i < nSize ;++i)
    {
        sum += parr[i];
    }
    return sum;
}
int _tmain(int argc, _TCHAR* argv[])
{
    int nArr[] = {1,2,3,4};
    int nSum = Sum(nArr);
   std::cout<<"Sum :"<<nSum;
}

Может ли std::vector использоваться вместо array . Или array может быть заменен любым из контейнеров stl?

Ответы [ 3 ]

4 голосов
/ 23 сентября 2019

Может ли std::vector использоваться вместо массива . Или массив может быть заменен любым из контейнеров stl?

Нет,Это невозможно, так как они разные по своим типам.Но вы можете обобщить данную функцию следующим образом.

Создайте шаблонную функцию, принимающую начальный и конечный итераторы контейнера.Затем, используя std::accumulate, суммируйте элементы, которые будут работать для любых контейнеров последовательности , а также массивов:

пример кода: ( Смотреть онлайн )

#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <numeric>  // std::accumulate
#include <iterator> // std::iterator_traits, std::cbegin, std::cend

template<typename Iterator>
constexpr auto Sum(Iterator begin, const Iterator end) -> typename std::iterator_traits<Iterator>::value_type
{
    using RetType = typename std::iterator_traits<Iterator>::value_type;
    return std::accumulate(begin, end, RetType{});
}

int main()
{
    int nArr[] = { 1,2,3,4 };
    std::vector<int> vec{ 1,2,3,4 };
    std::list<int> list{ 1,2,3,4 };
    // now you can
    std::cout << "Sum of array: " << Sum(std::cbegin(nArr), std::cend(nArr)) << "\n";
    std::cout << "Sum of vec: "   << Sum(std::cbegin(vec), std::cend(vec)) << "\n";
    std::cout << "Sum of list: "  << Sum(std::cbegin(list), std::cend(list)) << "\n";
}

Вывод :

Sum of array: 10
Sum of vec: 10
Sum of list: 10
2 голосов
/ 23 сентября 2019
template<typename T, int nSize>
T sum(std::array<T, nSize> const&);

будет эквивалентной подписью для std::array.Как видите, подпись уже отличается.Попытка сделать то же самое для std::vector обречена на неудачу:

template<typename T, int nSize>
T sum(std::vector<T> const&);

Как вы могли бы узнать уже во время компиляции , сколько элементов будет находиться в векторе ???Вы просто не можете.Даже если вы указали nSize в коде явно, например, sum<std::vector<int>, 7>, функция тогда будет всегда пытаться выполнить итерацию ровно по семи элементам, что приведет к неопределенному поведению, если их меньше, и не учитывать лишние, еслиЕсть и другие ...

Типичный путь - использование итераторов начала и конца, как это делает стандартная библиотека для всех своих алгоритмов:

template <typename Iterator>
auto sum(Iterator begin, Iterator end) -> std::remove_reference_t<decltype(*begin)>
{
    using type = decltype(sum(begin, end)); // just not wanting to repeat all
                                            // that remove_reference stuff...
    type s = type();
    for( ; begin != end; ++begin)
    {
        s += *begin;
    }
    return s;
}

Вы дополнительноможет, основываясь на этой функции, обеспечить общую перегрузку для произвольных контейнеров:

template <typename Container>
auto sum(Container const& c)
{
    using std::begin;
    using std::end;
    return sum(begin(c), end(c));
}
0 голосов
/ 23 сентября 2019

Если ваш компилятор поддерживает C ++ 17, вы можете написать одну функцию с помощью оператора if constexpr.

Например,

#include <iostream>
#include <vector>

template<typename T>
auto Sum( const T &container )
{
    if constexpr( std::is_array_v<std::remove_reference_t<T>> )
    {
        std::remove_extent_t<T> sum = 0;
        for ( const auto &item : container )
        {
            sum += item;
        }

        return sum;
    }
    else
    {
        typename T::value_type sum = 0;
        for ( const auto &item : container )
        {
            sum += item;
        }

        return sum;
    }
}

int main()
{
    int nArr[] = { 1, 2, 3, 4 };
    int nSum = Sum( nArr );
    std::cout << "Sum :"<<nSum << '\n';;

    std::vector<int> v = { 1, 2, 3, 4 };
    nSum = Sum( v );
    std::cout << "Sum :"<<nSum << '\n';;
}

Вывод программы:

Sum :10
Sum :10

Однако лучше разделить функцию на две функции: одну для массивов и другую для стандартных контейнеров.

#include <iostream>
#include <vector>

template<typename T, size_t N>
auto Sum( const T ( &a )[N] )
{
    T sum = 0;

    for ( const auto &item : a )
    {
        sum += item;
    }

    return sum;
}

template<typename T>
auto Sum( const T &container )
{
    typename T::value_type sum = 0;
    for ( const auto &item : container )
    {
        sum += item;
    }

    return sum;
}

int main()
{
    int nArr[] = { 1, 2, 3, 4 };
    int nSum = Sum( nArr );
    std::cout << "Sum :"<<nSum << '\n';;

    std::vector<int> v = { 1, 2, 3, 4 };
    nSum = Sum( v );
    std::cout << "Sum :"<<nSum << '\n';;
}
...