具有两个参数包的函数模板重载决议

Function template overload resolution with two parameter packs

考虑以下代码:

#include<iostream>

template<class..., class... T>
int f(T...) { return 1; }

template<class... T>
int f(T...) { return 2; }

int main()
{
    std::cout << f(1);
}

它在 gcc 8.2 上编译并打印 1,但在 clang 7 上编译失败,因为调用 f(1) 不明确。

如果调用被替换为 f(),两个编译器都无法编译,声称调用不明确。

如果参数包 class... T 被简单的参数 class T 替换(并且 T...T 替换),两个编译器也声称有歧义。

第一个例子中哪个编译器符合标准?我想这归结为函数模板的特定部分排序规则,或者以这种方式使用双参数包是否已经不正确?

编辑:

我的理解是,如果第二个包可以从函数参数中推导出来,我的阅读中 [temp.param] 17.1/15 似乎明确允许这样做似乎是这样,因为T...函数参数包。

也可以明确指定第一个参数包的参数,但不是第二个参数包,因此(在模板参数推导之后)至少一个参数包为空的情况并不总是如此。我不确定这是否会使程序格式错误,因为我不知道如何阅读,例如[temp.res] 17.7/8.3 在这种情况下。

gcc 和 clang 似乎都适用于双参数包本身,例如当删除第二个函数模板重载时,两个编译器都打印 1。但这可能是格式错误的情况,不需要诊断

此外,我假设使用 class 模板参数推导,一个可变参数 class 模板可以定义一个可变参数构造函数模板,这意味着构造函数候选类似于我的双参数包示例,并且作为据我了解,在该上下文中会发生相同的重载决议和模板参数推导。这个问题是由具有这种设置的另一个问题引起的:Variadic class template deduction fails with gcc 8.2, compiles with clang and msvc 另见有关讨论:

现在我也找到了问题 的答案,我认为这意味着 gcc 是错误的,调用应该被认为是模棱两可的,但我想让它验证这同样适用于这里方法。我也欢迎提供更详细的推理,因为函数模板偏序规则对我来说似乎很不清楚。

这里有两个问题。


首先,[temp.deduct.partial]/12(我也引用了这个例子,因为它与你的相似)说:

In most cases, deduction fails if not all template parameters have values, but for partial ordering purposes a template parameter may remain without a value provided it is not used in the types being used for partial ordering. [ Note: A template parameter used in a non-deduced context is considered used. — end note ] [ Example:

template <class T> T f(int);            // #1
template <class T, class U> T f(U);     // #2
void g() {
  f<int>(1);                            // calls #1
}

— end example ]

根据[temp.deduct.partial]/3

,用于部分排序的类型是T...

The types used to determine the ordering depend on the context in which the partial ordering is done:

  • In the context of a function call, the types used are those function parameter types for which the function call has arguments.

  • ...

所以第一个未命名的模板参数包class...不影响偏序的结果。由于这两个函数模板没有其他区别,因此两者都不比另一个更专业,从而导致调用不明确。

可能与GCC的bug 49505有关。


其次,即使第二个函数模板不存在,调用仍然应该是格式错误的。根据 [temp.arg.explicit]/3

... A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments ...

只有 trailing 模板参数包可以推导为空包,而第一个未命名的模板参数包 class... 不是 trailing模板参数包。

两个 GCC (bug 69623) and Clang (bug 26435) 都有针对此问题的错误。