1

I have a exercise in C++ Primer 6th:

Complete the program by supplying the average_list() function. It should be a template function, with the type parameter being used to specify the kind of initialized_list template to be used as the function parameter and also to give the function return type.

I have no idea with it

Here is part of a short program:

int main() {
     using namespace std;
     // list of double deduced from list contents
     auto q = average_list({15.4, 10.7, 9.0});
     cout << q << endl;
     // list of int deduced from list contents
     cout << average_list({20, 30, 19, 17, 45, 38} ) << endl;
     // forced list of double
     auto ad = average_list<double>({'A', 70, 65.33});
     cout << ad << endl;
}
Ami Tavory
  • 74,578
  • 11
  • 141
  • 185

2 Answers2

1

You might go with something like this:

#include <iterator>                                                                                                                                                                                          
#include <numeric>
#include <iostream>
#include <initializer_list>

template <typename T>
auto average_list(const std::initializer_list<T> &&v) -> decltype(T() / 1.0)
{
    return std::accumulate(std::begin(v), std::end(v), T()) / static_cast<float>(std::distance(std::begin(v), std::end(v)));
}

The line

auto average_list(const std::initializer_list<T> &&v) -> decltype(T() / 1.0)

Says that average_list takes an initializer list const reference to some type T, and returns the type obtained by dividing a T by a float.

The function's body simply uses STL functions from numeric and such.

Ami Tavory
  • 74,578
  • 11
  • 141
  • 185
  • You don't need to take `std::initializer_list` by `const&`. – Simple Jan 18 '16 at 15:16
  • @Simple Thanks, I see your point. I like doing this if only as "documentation" for myself that there's only an intent to go over and not modify. Again, you have a point. – Ami Tavory Jan 18 '16 at 15:18
  • Thanks for you answer. But why using T()? What does this mean? – Daniel Powter Jan 20 '16 at 15:25
  • @M.Daniel See [here](http://stackoverflow.com/questions/5113365/do-built-in-types-have-default-constructors) for the meaning of `int()`, e.g.. I've often seen the convention that, consequently, numeric-like types should have a default constructor that initializes to something like 0. – Ami Tavory Jan 20 '16 at 15:39
0

You need to write a parametrized function that uses a template which makes the type of the variable a parameter.

The type of the passed values then can be deduced by the compiler which specializes your function to handle the type that was passed.

Judging by the name average_list(), the function should return the average value of the arguments passed, thus you need to write the code to make that, starting from a one type, for example int and then simply replace int with a template parameter. The syntax to do this is:

template <typename T> // prefix in front of the function

Example: the function below handles only int

int sum_vector(const std::vector<int>& v) {
    int sum = 0;      

    for (size_t i = 0; i < v.size(); ++i){
       // accumulate sum
       sum += v[i];
    }
    return sum;
}

to make the type of the above function parameter, you could write:

template<typename T> T sum_vector(const std::vector<T>& v) {
    T sum = 0;      

    for (size_t i = 0; i < v.size(); ++i){
        // accumulate sum
        sum += v[i];
    }
    return sum;
}

then T is determined depending on the type of the vector passed as an argument, i.e. if the type of the vector is int, every T "becomes"1 an int, if double then every T "becomes" a double.


1. The compiler gets you a function instantiation with type int.

Ziezi
  • 6,375
  • 3
  • 39
  • 49