When running this:
template <typename T>
struct CodeByType
{
static const int32_t Value = 7;
};
template <>
struct CodeByType<int>
{
static const int32_t Value = 1;
};
template <typename Arg, typename... Args>
int32_t Sum()
{
// The compiler complains on this line
return Sum<Arg>() + Sum<Args...>();
}
template <typename Arg>
int32_t Sum()
{
return CodeByType<Arg>::Value;
}
int main()
{
auto sum = Sum<int, char, double>();
}
I'm getting:
Error C2668 'Sum': ambiguous call to overloaded function
Can someone please explain why and how to overcome it?
This looks awfully similar to the below code, which does compile, so I suppose it has something to do with Sum
not accepting any actual parameters.
template <typename T>
T adder(T first) {
return first;
}
template<typename T, typename... Args>
T adder(T first, Args... rest) {
return first + adder(rest...);
}
int main()
{
auto sum = adder(1, 7);
}
If you reduce your code to just:
Sum<int>();
You get a more helpful error message:
31 : <source>:31:16: error: call to 'Sum' is ambiguous auto sum = Sum<int>(); ^~~~~~~~ 17 : <source>:17:9: note: candidate function [with Arg = int, Args = <>] int32_t Sum() ^ 24 : <source>:24:9: note: candidate function [with Arg = int] int32_t Sum() ^ 1 error generated.
So it is clearer that there is an overload ambiguity between the first overload with Args = <>
and the second one. Both are viable.
One would might think as specialization for a solution:
template <typename Arg>
int32_t Sum<Arg>()
{
return CodeByType<Arg>::Value;
}
which would indeed solve the issue, had it been allowed by the standard. Partial function specializations are not allowed.
This is the most elegant solution:
constexpr if to the rescue:
template <typename Arg, typename... Args>
int32_t Sum()
{
if constexpr(sizeof...(Args) == 0)
return CodeByType<Arg>::Value;
else
return Sum<Arg>() + Sum<Args...>();
}
We use SFINAE to enable/disable the function we want. Please note the function definition order had to be reversed.
template <typename Arg, typename... Args>
auto Sum() -> std::enable_if_t<(sizeof...(Args) == 0), int32_t>
{
return CodeByType<Arg>::Value;
}
template <typename Arg, typename... Args>
auto Sum() -> std::enable_if_t<(sizeof...(Args) > 0), int32_t>
{
return Sum<Arg>() + Sum<Args...>();
}
just replace std::enable_if_t<>
with typename std::enable_if<>::type
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With