Template function

I have a problem writing a template function that takes the mean of a container. The container should either be a vector or an array and should work with all arithmetic types. This is what I have come up with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <vector>
#include <stdexcept>


using namespace std;


template<class T,class iter>
T median(iter begin, iter end ){
    if ( begin == end)
    {
        throw domain_error("median of empty container!");
    }
    sort(begin, end);
    size_t size = end - begin;
    size_t mid = size / 2;
    
    T median = size % 2 == 0 ? (*(begin + mid) + *(begin + mid - 1)/2) : *(begin + mid);
    return median;
    
}


I get a "no matching function error" and I guess the problem is caused by the value of type T. If I write this only for one specific type such as int or double, the template function works for both vectors and arrays, but it doesn't work if I try to write it for all arithmetic types.

I assume that the problem is that I don't pass any parameter with type T to the function, but I don't know how I would do this in this case without passing some parameter that doesn't really have any purpose besides indicating what type T is.
firstly, you have naming conflicts w/ the median variable declared inside the median function

AFAIK, you can omit the second template argument since it is automatically assigned because of the function parameter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <array>
using namespace std;

template <class T, class Iterator>
T median( Iterator first, Iterator last )
{
    // some computation
    
    T temp; //  = some computation
    return temp;
}

int main()
{
    array<int, 5> vals { 1, 2, 3, 12, 34 };
    median<int>( vals.begin(), vals.end() );
}
Last edited on
Thanks for your answer.

I tried that approach before, meaning that I declared a variable of type T ( temp in your case) and assigned the result of the computation, i.e. the median value, to that variable, but it still does not work for me. I still get the same error ("no matching function").

Why do you have to include <array>? Aren't arrays built into the language? Arrays are not part of the standard library to my knowledge. Also the member functions begin() and end() should not work with traditional arrays since arrays are not a class.


Why do you have to include <array>? Aren't arrays built into the language? Arrays are not part of the standard library to my knowledge. Also the member functions begin() and end() should not work with traditional arrays since arrays are not a class.

Yes, traditional arrays are built in into the language and is not a class.

But the Standard Template Library has it's own container which encapsulates c-style arrays into a template class.
And yes, it has a member function begin(), end(), size() etc. just other containers like vector(but of course it doesn't have members that modifies it's size like like push_back since array is not dynamic)
(See this link for more info: http://www.cplusplus.com/reference/array/array/ )
Note:
you should enable -std=c++11 to be able to use std::array

As per your problem, can you post the full error message and the code ?

This one works for me: w/ -std=c++11]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <iterator> // for begin() and end() (for c style array)
using namespace std;

template <class T, class Iterator>
T add( Iterator first, Iterator last )
{
    T temp = 0;
    while( first != last ) {
        temp += *first;
        first++;
    }
    return temp;
}

int main()
{
    int arr[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    // you can use the function begin() and end() frm.
    // <iterator> for c-style arrays
    auto i = add<int>( begin(arr), end(arr) );
    cout << "Sum: " << i;
    
}
Sum: 45
Last edited on
I'm sure someone can do this more elegantly than I can, but here's a version which doesn't require specifying a type:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdexcept>
#include <algorithm>
#include <vector>
#include <iterator>
#include <iostream>
#include <type_traits>

template <typename iter_type>
auto median(iter_type beg, iter_type end) -> typename std::remove_reference<decltype(*beg)>::type
{
    if (beg == end)
        throw std::domain_error("median of empty container");
    
    std::sort(beg, end);

    std::size_t size = end - beg;
    std::size_t mid = size / 2;

    if (size % 2)
        return *(beg + mid);

    return (*(beg + mid - 1) + *(beg + mid)) / 2;
}

int main()
{
    int arr [] = { 9, 7, 5, 3, 1, 8, 6, 4, 2 };
    std::vector<double> v = { 9.1, 7.2, 5.3, 3.4, 1.5, 8.6, 6.7, 4.8, 2.9 };

    std::cout << median(std::begin(arr), std::end(arr)) << '\n';
    std::cout << median(std::begin(v), std::end(v)) << '\n';
}


http://ideone.com/FpX7gJ
You could improve this by sorting only as much as necessary:

1
2
3
4
5
6
    std::size_t size = end - beg;
    std::size_t mid = size / 2;

    std::nth_element(beg, beg + mid, end);
    return beg[mid]; // odd case
}
Last edited on
Topic archived. No new replies allowed.