如何在c ++中使用泛型函数?

时间:2015-08-27 14:15:21

标签: c++ templates precision

我编写了这段代码,如果我取消注释第二行,我会收到错误 - “模板参数推断/替换失败:”。是因为C ++中泛型函数的一些限制吗?此外,我的程序不会打印数组b的浮动答案。有什么我可以做的吗? (抱歉在单个帖子中提出2个问题。)
P.S:我刚开始学习C ++。

#include <iostream>
 using namespace std;

 template <class T>
 T sumArray(  T arr[], int size, T s =0)
 {
     int i;
     for(i=0;i<size;i++)
     {  s += arr[i];
     }
     return s;
 }

 int main()
 {
     int a[] = {1,2,3};
     double b[] = {1.0,2.0,3.0};
     cout << sumArray(a,3) << endl;
     cout << sumArray(b,3) << endl;
     cout << sumArray(a,3,10) << endl;
     //cout << sumArray(b,3,40) << endl; //uncommenting this line gives error

     return 0;
 }

左编辑1:将40更改为40.0后,代码可以正常工作。这是我得到的输出:
6
6
16
46 我在第二种情况下仍然没有得到浮动答案。有什么建议吗?

7 个答案:

答案 0 :(得分:19)

原因是编译器无法推断出Memory Address Values 1000 0x39 1001 0x05 1002 0x00 1003 0x00 的类型。

它应该如何理解你最后一个例子的T是什么?第一个参数(T)的类型是b,而在函数定义中它是double[]。因此,T[]看起来应该是T。但是,第三个参数(double)的类型为40,因此看起来int应为T。因此错误。

int更改为40会使其有效。另一种方法是在模板声明中使用两种不同的类型:

40.0

请注意,我必须明确地将#include <iostream> using namespace std; template <class T, class S = T> T sumArray( T arr[], int size, S s =0) { int i; T res = s; for(i=0;i<size;i++) { res += arr[i]; } return res; } int main() { int a[] = {1,2,3}; double b[] = {1.0,2.0,3.1}; cout << sumArray(a,3) << endl; cout << sumArray(b,3) << endl; cout << sumArray(a,3,10) << endl; cout << sumArray(b,3,40) << endl; //uncommenting this line gives error return 0; } 投射到s,否则最后一个示例将丢失小数部分。

但是,此解决方案仍不适用于T,因为它会将sumArray(a,3,10.1)转换为10.1,因此如果这也是一个可能的用例,则需要更准确的处理。使用c ++ 11功能的完整工作示例可能类似于

int

此模板功能的另一个可能的改进是自动推断数组大小,请参阅TartanLlama的答案。

答案 1 :(得分:4)

sumArray(b,3,40)

40的类型为int,但b的类型为double[3]。当您将这些作为参数传递时,编译器将获得T的冲突类型。

解决此问题的一种简单方法是传入double

sumArray(b,3,40.0)

但是,您可能最好通过添加另一个模板参数来允许在呼叫站点进行转换。您还可以添加一个来为您推断出数组的大小,这样您就不需要明确地传递它:

template <class T, class U=T, std::size_t size>
U sumArray(T (&arr) [size], U s = 0)

U参数默认为T,以支持s的默认值。请注意,为了推断出数组的大小,我们需要传递对它的引用而不是传递值,这会导致它衰减为指针。

现在调用如下:

sumArray(b,40)

Live Demo

答案 2 :(得分:3)

template <class T>
T sumArray(  T arr[], int size, T s =0)
             ^                  ^

两者(可推导)T应匹配。

sumArray(b, 3, 40)中,第一个为double,第二个为int

解决问题有几种可能性

    在通话网站
  • ,请致电sumArray(b, 3, 40.0)sumArray<double>(b, 3, 40);

  • 使用额外参数:

    template <typename T, typename S>
    auto sumArray(T arr[], int size, S s = 0)
    

    根据您的需要,返回类型可以是TSdecltype(arr[0] + s)

  • 使参数不可导出:

    template <typename T> struct identity { using type = T;};
    // or template<typename T> using identity = std::enable_if<true, T>;
    
    template <typename T>
    T sumArray(T arr[], int size, typename identity<T>::type s = 0)
    

答案 3 :(得分:2)

应该是

sumArray(b,3,40.0)

因此,T将推断为double。在您的代码中,它是int

答案 4 :(得分:1)

扣除失败时的另一个选择是明确告诉编译器你的意思:

cout << sumArray<double>(b,3,40) << endl;

答案 5 :(得分:0)

编译器不知道T应该是int还是double

您可能希望执行以下操作,以保持传递类型的最高精度:

template <class T, class S>
std::common_type_t <T, S> sumArray (T arr [], std::size_t size, S s = 0)
{
   std::common_type_t <T, S> sum = s;
   for (std::size_t i = 0; i != size; ++i)
   {
      sum += arr[i];
   }
   return sum;
}

但是,您正在编写的功能已经存在。这是std::accumulate

std::cout << std::accumulate (std::begin (b), std::end (b), 0.0) << std::endl;

答案 6 :(得分:-1)

模板只接受一种类型的数据,例如,如果发送一个double数组,那么运行时将推断:

Template = double []

所以每次他都会看到它,他会期待一系列的双打。

sumArray(b,3,40)传递“b”(这是一个双精度数组)但是你传递“40”,运行时不能隐式转换为double。

所以代码

sumArray(b,3,40.0)

将起作用