Reputation: 89
I want to calculate the sum of any number of arguments given to function sum
. Assuming that integers given to the function will satisfy operator+
.
If I comment out the function sum()
(the one having no arguments), the code does not compile. And if I uncomment it, the code does compile and run, but never hits the function sum()
.
I can't seem to understand that why do we need to have sum()
function at all as I am using condition on sizeof...(Args)
Will really appreciate it if someone can help me understand this?
/*
int sum()
{
std::cout << "Sum with 0 Args" << std::endl;
return 0;
}
*/
template <typename T, typename...Args>
T sum(T first, Args...args)
{
// std::cout << sizeof...(Args) << std::endl;
if (sizeof...(Args) != 0)
{
return first + sum(args...);
}
else
{
std::cout << "Found 0 args" << std::endl;
return first;
}
}
int main()
{
std::cout << sum(1, 2, 3) << std::endl;
std::cout << sum(1.2, 3.5) << std::endl;
return 0;
}
Once I uncomment function sum(), I get below output -
Found 0 args
6
Found 0 args
4.7
Basically sum()
never get called which is expected, but then why do we need it in the first place?
Upvotes: 0
Views: 150
Reputation: 32952
Basically
sum()
never get called which is expected but then why do we need it in the first place?
When you use the normal if
statement, like in your code, the both branches are checked, and both must be compilable. When the sum
is called recursively, the last function call is with no arguments. For this case to be true, the compiler requires a sum
function with no arguments.
On the other hand, since c++17, we have if constexpr
, by which we can retain only the true branches at compile time. That means, just changing the code as follows, you no longer required the sum()
with no argument anymore.
Read more here: Difference between if constexpr
and if
?
template <typename T, typename...Args>
T sum(T first, Args...args)
{
if constexpr (sizeof...(Args) != 0)
// ^^^^^^^^^^
{
// .... as before
}
else {
// .... as before
}
}
However, in c++11 or c++14, you may achieve a single sum
function, by slightly tricky/ hacky † fold expression:
#include <type_traits> // std::common_type
template <typename...Args>
auto sum(Args...args) -> typename std::common_type<Args...>::type
{
using unused = int[];
typename std::common_type<Args...>::type total{};
return static_cast<void>(unused{ 0, (total += args, 0)...}), total;
}
See a live demo in godbolt.org
† References:
Upvotes: 5
Reputation: 13076
I missed the C++11 requirement earlier. Here is an example that should be C++ compatible. Demo here : https://onlinegdb.com/js_WXEeiC
#include <iostream>
namespace details
{
template<typename arg1_t>
inline constexpr bool same_type()
{
return true;
}
template<typename arg1_t, typename arg2_t, typename... args_t>
inline constexpr bool same_type()
{
return std::is_same<arg1_t, arg2_t>::value && same_type<arg2_t, args_t...>();
}
template<typename arg_t>
arg_t sum(arg_t value)
{
return value;
}
template<typename arg_t, typename... args_t>
arg_t sum(arg_t value, args_t... values)
{
return value + sum(std::forward<args_t>(values)...);
}
}
template<typename arg_t, typename... args_t>
auto sum(arg_t value, args_t... values)
-> typename std::enable_if<details::same_type<arg_t, args_t...>(), arg_t>::type
{
return details::sum(value, values...);
}
int main()
{
static_assert(details::same_type<int>());
static_assert(details::same_type<int, int>());
static_assert(details::same_type<int, int, int>());
static_assert(!details::same_type<int, int, double>());
std::cout << sum(1, 2, 3);
return 0;
}
Upvotes: 0
Reputation: 13076
From C++17 you can use a fold expression for you recursive bit, and you have to use if constexpr for compile time if.
#include <iostream>
template<typename... args_t>
auto sum(args_t&&... args)
{
if constexpr (sizeof...(args_t) == 0)
{
return 0;
}
else
{
return (args + ...);
}
}
int main()
{
std::cout << sum() << "\n";
std::cout << sum(1, 2, 3);
return 0;
}
Upvotes: 0