可以在 stl 容器上完成非类型模板参数吗?

Can non type template arguments done on stl containers?

本文关键字:类型 参数 stl      更新时间:2023-10-16
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可以代替数组使用。或者阵列可以用任何 stl 容器替换吗?

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
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>,该函数总是尝试迭代恰好七个元素,如果元素较少,则导致未定义的行为,如果元素更多,则不计算多余的元素......

典型的方法是使用 begin 和 end 迭代器,就像标准库对其所有算法所做的那样:

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));
}

如果您的编译器支持 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';;
}