简体   繁体   English

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

[英]How to use generic function in c++?

I have written this code in which if I uncomment the 2nd last line I get error - "template argument deduction/substitution failed: ". 我编写了这段代码,如果我取消注释第二行,我会收到错误 - “模板参数推断/替换失败:”。 Is it because of some limit to generic functions in C++? 是因为C ++中泛型函数的一些限制吗? Also my program doesn't print floating answer for the array b . 此外,我的程序不打印阵列b浮动答案。 Is there anything I can do for that? 有什么我可以做的吗? (sorry for asking 2 questions in single post.) (抱歉在单个帖子中提出2个问题。)
PS: I have just started learning C++. PS:我刚开始学习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;
 }


EDIT 1: After changing 40 to 40.0, the code works. 编辑1:更改40到40.0后,代码工作。 Here is the output I get: 这是我得到的输出:
6 6
6 6
16 16
46 46
I still don't get the floating answer in 2nd case. 在第二种情况下,我仍然没有得到浮动答案。 Any suggestion ? 有什么建议吗?

The reason is that compiler can not deduce the type for T . 原因是编译器无法推断出T的类型。

How it should understand what T is for your last example? 它应该如何理解你最后一个例子的T是什么? The type of the first argument ( b ) is double[] , while it is T[] in the function definition. 第一个参数( b )的类型是double[] ,而函数定义中是T[] Therefore it looks like that T should be double . 因此看起来T应该是double However, the type of the third argument ( 40 ) is int , so it looks like T should be int . 但是,第三个参数( 40 )的类型是int ,所以看起来T应该是int Hence the error. 因此错误。

Changing 40 to 40.0 makes it work. 40改为40.0可以使它工作。 Another approach is to use two different types in template declaration: 另一种方法是在模板声明中使用两种不同的类型:

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

Note that I had to cast s to T explicitly, otherwise the last example will lose fractional part. 请注意,我必须明确地将sT ,否则最后一个示例将丢失小数部分。

However, this solution will still not work for sumArray(a,3,10.1) because it will cast 10.1 to int , so if this is also a possible use case, a more accurate treatment is required. 但是,此解决方案仍然不适用于sumArray(a,3,10.1)因为它会将10.1int ,因此如果这也是一个可能的用例,则需要更准确的处理。 A fully working example using c++11 features might be like 使用c ++ 11功能的完整工作示例可能是这样的

 template <class T, class S = T>
 auto sumArray(T arr[], int size, S s=0) -> decltype(s+arr[0])
 {
    int i;
    decltype(s+arr[0]) res = s;
    ...

Another possible improvement for this template function is auto-deduction of array size, see TartanLlama's answer. 此模板功能的另一个可能的改进是自动推断数组大小,请参阅TartanLlama的答案。

sumArray(b,3,40)

The type of 40 is int , but the type of b is double[3] . 40的类型是int ,但b的类型是double[3] When you pass these in as arguments, the compiler gets conflicting types for T . 当您将这些作为参数传递时,编译器会获得T冲突类型。

A simple way to fix this is to just pass in a double : 解决这个问题的一个简单方法是传入一个double

sumArray(b,3,40.0)

However, you would probably be better off allowing conversions at the call site by adding another template parameter. 但是,您可能最好通过添加另一个模板参数来允许在呼叫站点进行转换。 You can also add one to deduce the size of the array for you so that you don't need to pass it explicitly: 您还可以添加一个来推断数组的大小,以便您不需要显式传递它:

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

The U parameter is defaulted to T to support the default value for s . U参数默认为T以支持s的默认值。 Note that to deduce the size of the array, we need to pass a reference to it rather than passing by value, which would result in it decaying to a pointer. 请注意,为了推断出数组的大小,我们需要传递对它的引用而不是传递值,这会导致它衰减为指针。

Calling now looks like this: 现在调用如下:

sumArray(b,40)

Live Demo 现场演示

In

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

Both (deducible) T should match. 两者(可推导) T应匹配。

In sumArray(b, 3, 40) , it is double for the first one, and int for the second one. sumArray(b, 3, 40) ,第一个是double ,第二个是int

There is several possibilities to fix problem 有几种方法可以解决问题

  • at the call site, call sumArray(b, 3, 40.0) or sumArray<double>(b, 3, 40); 在呼叫站点,调用sumArray(b, 3, 40.0)sumArray<double>(b, 3, 40);

  • Use extra parameter: 使用额外参数:

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

    Return type may be T , S , or decltype(arr[0] + s) depending of your needs. 返回类型可以是TSdecltype(arr[0] + s)具体取决于您的需要。

  • make a parameter non deducible: 使参数不可推导:

     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) 

Should be 应该

sumArray(b,3,40.0)

so, T will be deduced to double . 所以, T将被推断为double In your code it's int . 在你的代码中它是int

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

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

The compiler does not know whether T should be int or double . 编译器不知道T应该是int还是double

You might want to do the following, in order to preserve the highest precision of the types passed: 您可能希望执行以下操作,以保持传递的类型的最高精度:

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

The function you are writing, however, already exists. 但是,您正在编写的功能已经存在。 It's std::accumulate : 这是std::accumulate

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

Templates only accept one type of data, for example if you send an array of double, then the runtime will deduce : 模板只接受一种类型的数据,例如,如果发送一个double数组,那么运行时将推断:

Template = double[] Template = double []

so every time he will see it he will expect an array of doubles. 所以每当他看到它,他都会期待一系列的双打。

sumArray(b,3,40) passes "b" (which is an array of doubles) but then you pass "40" which the runtime cannot implicitly convert to double. sumArray(b,3,40)传递“b”(这是一个双精度数组)但是然后传递“40”,运行时无法隐式转换为double。

So the code 所以代码

sumArray(b,3,40.0)

will work 将工作

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM