Ambiguous call to variadic template function with no parameters?

风流意气都作罢 提交于 2019-12-04 11:25:08

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.

C++17 solution:

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...>();
}

C++14 solution

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...>();

}

C++11 solution

just replace std::enable_if_t<> with typename std::enable_if<>::type

In c++17, it would simply be

template <typename... Args>
int32_t Sum()
{
    return (CodeByType<Args>::Value + ...); // Fold expression
}

In C++11, you may do:

template <typename... Args>
int32_t Sum()
{
    int32_t res = 0;
    const int32_t dummy[] = {0, (res += CodeByType<Args>::Value)...};
    static_cast<void>(dummy); silent warning about unused variable
    return res;
}

My memories of the template mechanism are old but if I recall correctly, their information is erased at a certain point in the compilation process.

My guess is that in the second case, the functions get distinguished not by the difference in the template types, but by the difference in the arguments.

In your case, you have no arguments, so stripped of the template information the two overloaded versions are equal and it cannot distinguish between them when you call it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!