我正在尝试编写一个模板函数,该函数采用任意数字类型的任意容器类:
template <typename NumType, typename ContType>
double avg_nums(const ContType<NumType> & data)
{
double sum = 0;
for(ContType::const_iterator iter = data.cbegin(); iter != data.cend(); ++iter)
{
if(typeid(NumType) == typeid(char) || typeid(NumType) == typeid(unsigned char))
{
std::cout << static_cast<int>(*iter) << std::endl;
}
else
{
std::cout << *iter << " ";
}
sum += *iter;
}
std::cout << std::endl;
return sum / data.size();
}
但这会产生语法错误(VS2012)。这也不起作用:
template <typename NumType, typename ContType<NumType> >
double avg_nums(ContType<NumType> & data)
我希望容器中的对象类型是模板参数以及容器类型,因此我可以添加对NumType的特定情况的检查。如果我将功能签名更改为
template <typename NumType, typename ContType>
double avg_nums(ContType & data)
它构建但现在它依赖于显式指定正确的模板参数:
std::vector<char> cvec = boost::assign::list_of(0) (1) (1) (2) (3) (5);
std::vector<int> ivec = boost::assign::list_of(0) (1) (1) (2) (3) (5);
avg_nums<char, std::vector<char>>(cvec);
avg_nums<int, std::vector<int>>(ivec);
如果我将签名更改为
template <typename ContType>
double avg_nums(ContType & data)
它可以工作,但现在我没有直接访问元素类型。我可以从容器类型(std::vector<int>
或std::list<unsigned char>
)获取元素类型吗?
答案 0 :(得分:4)
您可以使用此表单:
template <typename ContType>
double avg_nums(ContType & data)
然后将元素类型设为
typename ContType::value_type
答案 1 :(得分:1)
template <typename ContType>
double avg_nums(ContType & data)
虽然有效,但现在我无法直接访问元素类型。我可以从容器的类型(std :: vector或std :: list)中获取元素类型吗?
您可以通过嵌套类型提取标准容器中包含元素的类型:value_type
:
typedef typename ContType::value_type NumType;
我不认为我会实现该功能,因为您可以使用经过充分测试的现有算法:
int value = 0;
int total = std::accumulate(container.begin(), container.end(), value);
double avg = total * 1. / container.size();
答案 2 :(得分:1)
如果容器类型没有某种'value_type'(这是首选方式,因为这个依赖于值类型是第一个不是第一个模板参数),下面的模板特化变体也可能会很有趣必然如此):
// define some custom container where we do not have some kind of 'value_type'
template <typename... T> class CustomContainer {};
// forward declare the template function so we can deduce the type in a specialization
template <typename ContType> double avg_nums(ContType&);
// specialization that deduces ContType and NumType from a single template argument
// This works for all continers where the first template argument is the 'value_type'
// also note the Ts... which is a placeholder for possible other template arguments that need to be passed on
template <template <typename...> class ContType, typename NumType, typename... Ts>
double avg_nums(ContType<NumType, Ts...>&)
{
// so the work
return NumType(0);
}
int main(int,char**)
{
CustomContainer<int> cont;
avg_nums(cont);
return 0;
}
答案 3 :(得分:0)
针对您当前遇到的特定问题,您可以替换
template <typename NumType, typename ContType>
double avg_nums(const ContType<NumType> & data)
{
与
template< class ContType >
double avg_nums(ContType const& data)
{
using NumType = typename ContType::value_type;
循环头中的类型规范需要typename
。
更一般地说,你可以做到
template< template< class, class > class ContType_, class NumType, class Allocator >
double avg_nums(ContType_<NumType, Allocator> const& data)
{
using ContType = ContType_<NumType, Allocator>;
而不是
if(typeid(NumType) == typeid(char) || typeid(NumType) == typeid(unsigned char))
{
std::cout << static_cast<int>(*iter) << std::endl;
}
else
{
std::cout << *iter << " ";
}
您可以使用隐式促销并撰写
std::cout << +*iter << " ";
或者0+*iter
如果你发现更清楚的话。
顺便说一句,请考虑使用std::accumulate
。
另外,顺便提一下,请考虑如何处理空容器。
最后,您可以使用基于C ++ 11范围的for
代替显式迭代器用法。