[英]Ambiguous call to variadic template function with no parameters?
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 错误C2668'Sum':对重载函数的模糊调用
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. 这看起来非常类似于下面的代码,它编译,所以我想它与Sum
不接受任何实际参数。
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. 因此更清楚的是,第一次重载与Args = <>
和第二次重载之间存在过载模糊。 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: constexpr如果要救援:
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. 我们使用SFINAE来启用/禁用我们想要的功能。 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
只需用typename std::enable_if<>::type
替换std::enable_if_t<>
In c++17, it would simply be 在c ++ 17中,它只是
template <typename... Args>
int32_t Sum()
{
return (CodeByType<Args>::Value + ...); // Fold expression
}
In C++11, you may do: 在C ++ 11中,您可以:
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. 在您的情况下,您没有参数,因此剥离了两个重载版本相同的模板信息,并且在调用它时无法区分它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.