GCC 无法解析带有默认参数和以下参数包的方法调用

GCC can not resolve method call with defaulted parameter and following parameter pack

是否允许GCC因为歧义拒绝下面的代码?对我来说,它看起来像一个错误。 它与 msvc、clang 和 icc 编译良好。

看这里:https://godbolt.org/z/9fsnhx

#include <iostream>

class A
{
public:
    template<typename T>
    void Foo(int={}){
        std::cout << "A";
    }

    template<
        typename... T
        ,typename... Args
    >
    void Foo(int={}, Args&&... args)
    {    
        std::cout << "B";
    }
};

int main()
{
    A a;
    a.Foo<int>();
}

我认为这是一个 gcc 错误。正如 在评论中指出的那样,如果您为默认参数提供参数,gcc 接受 - 但在这种情况下这应该是无关紧要的。

这里要指出的相关规则是[temp.deduct.partial],第3段:

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.138

(脚注说):[​​=23=]

Default arguments are not considered to be arguments in this context; they only become arguments after a function has been selected.

第 11 段:

If, after considering the above, function template F is at least as specialized as function template G and vice-versa, and if G has a trailing function parameter pack for which F does not have a corresponding parameter, and if F does not have a trailing function parameter pack, then F is more specialized than G.

第 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 ]

简而言之,这里考虑偏序时:

  1. 默认参数无关紧要,我们只考虑将int作为第一个参数的两个函数模板。

  2. 第一次重载中的T和第二次重载中的T...没有关系。它们 not 在用于部分排序的类型集中,它们不是函数的参数。这类似于第 12 段中的示例,其中同样名为 T 的模板参数也不起作用。

所以基本上我们在以下时间点餐:

void Foo(int);
template <typename... Args> void Foo(int, Args&&...);

这是一个非常简单的案例,其中第一个更专业。 gcc 弄错了 - 我提交了 96602.