这两个可变参数函数之间的本质区别是什么?

What's the essential difference between these two variadic functions?

本文关键字:之间 区别 是什么 函数 参数 两个 变参      更新时间:2023-10-16

我一直被一个简单的可变模板函数所困扰:

constexpr size_t num_args () {
    return 0;
}
template <typename H, typename... T>
constexpr size_t num_args () {
    return 1 + num_args <T...> ();
}
int main () {
    std :: cout << num_args <int, int, int> ();
}

上面的函数不能编译,详见上面的链接问题和后续内容,但是下面的函数可以编译

template <typename T, typename... Args> void foo (T, Args...);
template <typename... Args> void foo (int, Args...);
void foo () {}
template <typename... Args>
void foo (int x, Args... args)
{
    std :: cout << "int:" << x;
    foo (args...);
}
template <typename T, typename... Args>
void foo (T x, Args... args)
{
    std :: cout << " T:" << x;
    foo (args...);
}
foo (int (123), float (123)); // Prints "int:123 T:123.0"

两者似乎使用了相同的语言机制,但为什么第一个是坏的,而第二个是好的?

区别在于第一个函数

constexpr size_t num_args () {
    return 0;
}

不是模板,所以不能像这样调用

num_args <T...> ();

我开始认为区别在于

foo (args...);

利用了重载而

num_args <T...> ();

利用专业化。

重载可以处理基本情况,但专门化不能用于函数模板(但可以用于类),这就是为什么auxilliary_class<Args...>::value是惯用的