Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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++? Also my program doesn't print floating answer for the array b. Is there anything I can do for that? (sorry for asking 2 questions in single post.)
P.S: I have just started learning 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. Here is the output I get:
6
6
16
46
I still don't get the floating answer in 2nd case. Any suggestion ?

like image 325
shane Avatar asked Aug 27 '15 14:08

shane


People also ask

What is generic function in C?

Generic functions are functions declared with one or more generic type parameters. They may be methods in a class or struct , or standalone functions. A single generic declaration implicitly declares a family of functions that differ only in the substitution of a different actual type for the generic type parameter.

How do you write a generic function?

Function types can create generics in the same way as normal functions, by adding the type parameter list <T> before the function type parameter list. You can use generics in the same places you'd add any other type in a function type (parameter or return types). Which then gets used as its own type.

Can you do generics in C?

Unlike C++ and Java, C doesn't support generics. How to create a linked list in C that can be used for any data type? In C, we can use a void pointer and a function pointer to implement the same functionality. The great thing about void pointer is it can be used to point to any data type.

What is generic data type in C?

Generics is the idea to allow type (Integer, String, … etc and user-defined types) to be a parameter to methods, classes and interfaces. For example, classes like an array, map, etc, which can be used using generics very efficiently. We can use them for any type.


2 Answers

The reason is that compiler can not deduce the type for T.

How it should understand what T is for your last example? The type of the first argument (b) is double[], while it is T[] in the function definition. Therefore it looks like that T should be double. However, the type of the third argument (40) is int, so it looks like T should be int. Hence the error.

Changing 40 to 40.0 makes it work. 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.

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. A fully working example using c++11 features might be like

 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.

like image 100
Petr Avatar answered Nov 15 '22 21:11

Petr


sumArray(b,3,40)

The type of 40 is int, but the type of b is double[3]. When you pass these in as arguments, the compiler gets conflicting types for T.

A simple way to fix this is to just pass in a 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. 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

like image 31
TartanLlama Avatar answered Nov 15 '22 19:11

TartanLlama