Variadic template max function trouble
Asked Answered
P

5

5

I am trying to write a variadic template for finding the maximum of an arbitrary amount of numbers (this is just for practicing variadic templates).

However, I have sort of hit a wall and can't understand why my current attempt simply does not work, and fails at compile time with the error:

prog.cpp: In function 'A myMax(A, A, Args ...) [with A = int, Args = {}]':
prog.cpp:7:35:   instantiated from 'A myMax(A, A, Args ...) [with A = int, Args = {int}]'
prog.cpp:22:26:   instantiated from here
prog.cpp:7:35: error: no matching function for call to 'myMax(int)'

My code is as follows:

#include <iostream>

template <typename A, typename ... Args>
A myMax(A a, A b, Args ... args)
{
   return myMax(myMax(a,b),args...);
}

template <typename A>
A myMax(A a,A b)
{
   if (a>b)
      return a;
   else
      return b;
}


int main()
{
   std::cout<<myMax(1,5,2);
}

Can anyone tell me how to fix my variadic template?

Prentice answered 14/1, 2012 at 4:24 Comment(1)
OK, but once you're done learning, please go back and use std::max :-)Introject
B
16

Just define the overload which takes two arguments above the variadic function template:

template <typename A> 
A myMax(A a,A b)      //this is an overload, not specialization
{
   if (a>b)
      return a;
   else
      return b;
}

template <typename A, typename ... Args>
A myMax(A a, A b, Args ... args)
{
   return myMax(myMax(a,b),args...);
}

Now it will work: http://www.ideone.com/R9m61

The overload should be visible at the point of instantiation, which is in the variadic function template.

Bucktooth answered 14/1, 2012 at 4:30 Comment(1)
Woah, this was a surprising answer to me. So simple! I was expecting something more complex about partial specialization vs overloading. Will it also work to add a function signature just after #include <iostream>? Ex: template <typename A> A myMax(A a, A b);Robby
K
4

A shorter variaton of the previous answer using std::max, try it here:

#include <iostream>

template <typename T> 
T Max(T a) 
{
    return a;
}

template <typename T, typename ... Args> 
T Max(T a, Args ... args) 
{
    return std::max(Max(args...), a);
}

int main() {
    std::cout << Max(14,45,87,66,99,888,554,21);
}
Koppel answered 12/5, 2017 at 21:29 Comment(1)
Don't say "above", since you can't be sure what order answers will be in, or which answers will remain undeleted. Instead, link to the answer via the share link below it.Beattie
S
1

Using constexpr, it is now possible to do something like the following:

template<typename num_t, num_t ...X>
constexpr num_t max_element(){
    const std::array<num_t, sizeof...(X)> vals{X...};
    num_t ret = 0;
    for(size_t i=0; i<sizeof...(X); i++)
        if(vals[i] > ret)
            ret = vals[i];
    return ret;
}

I tried going one step further, using simply:

const std::array<num_t, sizeof...(X)> vals{X...};
return *std::max_element(vals.cbegin(), vals.cend());

but the compiler complained (I forget exactly what it said. [Edit: see this question/answer which explains the situation for std::alogrithm more generally.]

Anyway, you use it simply as:

auto max_val =  max_element<int, 11, 88, 12, 2>();
assert(max_val == 88);
Shupe answered 5/11, 2015 at 18:55 Comment(0)
L
1
template<class T>
T Max(T a, T b)
{
    return (a > b ? a : b);
}

template<class T, class... a>
T Max(T x , a... z)
{
    T k = Max(z...);
    return (x > k ? x : k);
}

int main()
{
    cout << Max(14,45,87,66,99,888,554,21);
}
Loader answered 15/3, 2017 at 13:19 Comment(0)
P
1

Solution without extra binary overload:

template <typename... Ts>
auto Max(Ts... ts)
{
    auto a = (ts,...);
    auto max = [&](const auto& b)
    {
        return a = std::max(a, b);         
    };
    return ((max(ts)), ...);
}
int main() {
    std::cout << Max(11,4,87,2,99);
    return 0;
}
Pancreatotomy answered 24/2, 2023 at 14:54 Comment(1)
There is some overhead in my case unluckily, compiling with cl.exe -O2 for x32. In assembly code, it actually compares the last argument with itself.Parmesan

© 2022 - 2024 — McMap. All rights reserved.