递归调用variadic模板函数重载时的不明确调用

时间:2017-02-06 08:14:21

标签: c++ variadic-templates overload-resolution

考虑这段代码:

template<typename FirstArg>
void foo()
{
}

template<typename FirstArg, typename... RestOfArgs>
void foo()
{
    foo<RestOfArgs...>();
}

int main()
{
    foo<int, int, int>();
    return 0;
}

foo<RestOfArgs...>();只有一个元素(RestOfArgs)时,由于调用模糊{int}而无法编译。

但是这个编译没有错误:

template<typename FirstArg>
void foo(FirstArg x)
{
}

template<typename FirstArg, typename... RestOfArgs>
void foo(FirstArg x, RestOfArgs... y)
{
    foo(y...);
}

int main()
{
    foo<int, int, int>(5, 6, 7);
    return 0;
}

为什么第一种情况存在歧义?

为什么第二种情况没有歧义?

3 个答案:

答案 0 :(得分:1)

为什么第一种情况存在歧义?

RestOfArgs可以为空。

因此foo<int>可以实例化为:

template<int>
void foo()
{
}

template<int,>
void foo()
{
    foo<>();
}

两者都会编译,所以它很模糊。

实际上foo<>()不会编译,但在下一个实例化中失败,所以没关系。

为什么第二种情况没有歧义?

foo<int>(7)可以实例化为:

template<int>
void foo(int 7)
{
}

template<int>
void foo(int 7)
{
    foo();
}

但第二个是错误,因为没有foo没有参数,所以唯一的候选者是第一个,所以不会有歧义

答案 1 :(得分:1)

The answer by @ZangMingJie回答了您在代码中观察到的行为差异。

我发现通过以下更改更容易理解名称解析:

template<typename FirstArg>
void foo()
{
    printf("1\n");
}

template<typename FirstArg, typename SecondArg, typename... RestOfArgs>
void foo()
{
    printf("2\n");
    foo<SecondArg, RestOfArgs...>();
}

int main()
{
    foo<int, int, int>();
    return 0;
}

当使用两个或更多模板参数时,将调用第二个函数。当有一个模板参数时,将调用第一个函数。

答案 2 :(得分:1)

Function template overloading

有很多规则可以告诉哪些模板函数更专业(根据给定的参数)。

要点

template<typename> void foo();
template<typename, typename...> void foo();

foo<int>()不明确,但不是

template<typename T> void foo(T);
template<typename T, typename... Ts> void foo(T, Ts...);
foo(42)

如下:

  

如果一个平局,如果一个函数模板有一个尾随参数包而另一个没有,那么带有省略参数的那个被认为比具有空参数包的那个更专业。