C++ 中具有多个参数包的函数的重载解析

Fed*_*dor 15 c++ language-lawyer overload-resolution c++20 parameter-pack

一个 C++ 函数可以有多个参数包。虽然看起来不太实用,但了解它们的语言规则仍然很有趣。

例如,如果有两个重载:

constexpr int f(auto...) { return 1; }
constexpr int f(auto..., auto...) { return 2; }
Run Code Online (Sandbox Code Playgroud)

f不带参数的调用f()在 MSVC 中选择版本 1,在 Clang 中选择版本 2,ambiguous overloaded call在 GCC 中选择版本 2。

如果f使用参数调用f(1),则 MSVC 和 GCC 都选择版本 1,而 Clang 仍选择版本 2。

演示: https: //gcc.godbolt.org/z/PWr6h1dn1

这里是哪个编译器?

有一个类似的问题带有两个参数包的函数模板重载解析,但是

  • 那里的函数只有一个参数包作为函数参数(第二个参数包根本没有使用),
  • 该示例会导致所有测试的编译器中出现歧义错误(但是提到的编译器错误仍未解决)。实际上,在此示例中也可能出现歧义,但这里大多数编译器选择其中一个重载而不会出现错误。

eca*_*mur 1

在这两种情况下,这都会导致程序因不明确而被拒绝。

首先要注意的是

在函数调用的上下文中,使用的类型是函数调用具有参数的函数参数类型。

也就是说,只有提供的实际参数才有助于函数模板部分排序。因此,(2) 中前面的函数参数包的存在不会有助于一个函数模板相对于另一个函数模板的推导过程;它被推断为空并且不会进一步贡献。

现在,带有尾随包的部分排序的决胜局无济于事,因为两者都有一个尾随包:

[...] 如果有一个没有对应参数的G尾随函数参数包,并且如果没有尾随函数参数包,则比 更专业。FFFG

但两者都有一个尾随参数包,并且长度相同,因此“没有F相应参数”的语言(不可否认,这并不完全清楚;请参阅CWG 1395)也没有帮助。

我认为如果提供了模板参数(并且它们是那些将被推导的参数),那么(2)应该是首选,因为在这种情况下它的尾随函数参数包会更短。但这还很不清楚;clang 同意我的观点,但 gcc 和 MSVC 采取相反的做法。