运行时:
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>();
}
我得到了:
错误C2668'Sum':对重载函数的模糊调用
有人可以解释为什么以及如何克服它?
这看起来非常类似于下面编译的代码,因此我认为它与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);
}
答案 0 :(得分:6)
如果您将代码缩减为:
Sum<int>();
您会收到更有用的错误消息:
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.
因此更清楚的是,第一次重载与Args = <>
和第二次重载之间存在过载歧义。两者都是可行的。
人们可能认为解决方案的专业化:
template <typename Arg>
int32_t Sum<Arg>()
{
return CodeByType<Arg>::Value;
}
如果标准允许的话,这确实可以解决问题。不允许使用部分功能。
这是最优雅的解决方案:
constexpr if救援:
template <typename Arg, typename... Args>
int32_t Sum()
{
if constexpr(sizeof...(Args) == 0)
return CodeByType<Arg>::Value;
else
return Sum<Arg>() + Sum<Args...>();
}
我们使用SFINAE来启用/禁用我们想要的功能。请注意,必须颠倒功能定义顺序。
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...>();
}
只需将std::enable_if_t<>
替换为typename std::enable_if<>::type
答案 1 :(得分:2)
在c ++ 17中,它只是
template <typename... Args>
int32_t Sum()
{
return (CodeByType<Args>::Value + ...); // Fold expression
}
在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;
}
答案 2 :(得分:0)
我对模板机制的记忆很老但是如果我没记错的话,他们的信息会在编译过程中的某个时刻被删除。
我的猜测是,在第二种情况下,函数的区别不在于模板类型的差异,而在于参数的差异。
在你的情况下,你没有参数,所以剥离了两个重载版本相同的模板信息,当你调用它时它们无法区分它们。