函数模板重载解析期间的 MSVC 与 Clang/GCC 错误,其中一个函数模板包含参数包

use*_*570 5 c++ language-lawyer function-templates pack-expansion parameter-pack

当我使用参数包时,我注意到这样一种情况(如下所示)在 gcc 和 clang 中编译得很好,但在 msvc 中却不行:

template<class T> void func(T a, T b= T{})
{
    
}
template<class T, class... S> void func(T a, S... b)
{

}
 
int main()
{
    func(1); // Should this call succeed? 
}
Run Code Online (Sandbox Code Playgroud)

这是验证相同内容的链接:https://godbolt.org/z/8KsrcnMez

可以看到,上面的程序在 msvc 中失败,并显示错误消息:

<source>(13): error C2668: 'func': ambiguous call to overloaded function
<source>(6): note: could be 'void func<int,>(T)'
        with
        [
            T=int
        ]
<source>(2): note: or       'void func<int>(T,T)'
        with
        [
            T=int
        ]
<source>(13): note: while trying to match the argument list '(int)'
Run Code Online (Sandbox Code Playgroud)

但同样可以用 gcc 和 clang 编译得很好。

这里有哪个编译器?

use*_*570 1

MSVC 拒绝该代码是正确的。根据temp.func.order#5.example-2该调用func(1)是不明确的。标准中给出的例子如下:

注意:由于在调用上下文中,此类类型推导仅考虑存在显式调用参数的参数,因此会忽略某些参数(即,函数参数包、具有默认参数的参数和省略号参数)

template<class T         > void g(T, T = T());          // #3
template<class T, class... U> void g(T, U ...);         // #4

void h() {
 g(42);                                                // error: ambiguous
}
Run Code Online (Sandbox Code Playgroud)

这意味着在所讨论的示例中,调用func(1)也是不明确的。

勘误表

请注意,cppreference在下面给出的示例中有勘误表:

template<class T>
void g(T, T = T()); // #1
template<class T, class... U>
void g(T, U...);    // #2

void h()
{
   g(42); // calls #1 due to the tie-breaker between parameter pack and omitted parameter
}
Run Code Online (Sandbox Code Playgroud)

从上面的示例中可以看出,cpprefernce 错误地表示#1应选择第一个重载。

这已在我最近所做的编辑中修复。

  • 该标准实际上有一个示例说明此调用不明确:https://timsong-cpp.github.io/cppwp/n4861/temp.func.order#5.example-2 (2认同)
  • @user17732522另外,我还做了一个[编辑](https://en.cppreference.com/mwiki/index.php?title=cpp/language/function_template&amp;diff=140392&amp;oldid=139771)修复了cppreference上的示例。 (2认同)
  • 我并不是说标准中的示例绝对正确。[CWG 1395](https://open-std.org/JTC1/SC22/WG21/docs/cwg_defects.html#1395) 之后需要更正类似的示例,请参阅 https://github.com/cplusplus/draft/issues /2559。我只是想表明它可能不像引用 cppreference 那么直接,并且如果有一个相反的例子,“_同样可以从 temp.deduct.partial._ 推断出”可能并不明显。 (2认同)