为什么默认参数不能与参数包一起使用?

Why don't default parameters work alongside a parameter pack?

因为8.3.6 ([dcl.fct.default])/4,

In a given function declaration, each parameter subsequent to a parameter with a default argument shall have a default argument supplied in this or a previous declaration or shall be a function parameter pack.

应编译以下内容:

#include <iostream>

template<typename ...Ts>
void foo(int i=8, Ts... args)
{
    std::cout << "Default parameters \t= " << i << "\n";
    std::cout << "Additional params  \t= " << sizeof...(Ts) << "\n";
}

int main()
{
    foo();                  // calls foo<>(int)
    foo(1, "str1", "str2"); // calls foo<const char*, const char*>(int, const char*, const char*)
    foo("str3");            // ERROR: does not call foo<const char*>(int, const char*)

    return 0;
}

但由于 foo("str3") 混淆了编译器,它无法编译。它抱怨没有用于调用 foo(const char*) 的匹配函数,并且它无法将 "str3"(类型 const char*)转换为类型 int.

我知道可以通过诉诸函数重载或使用命名参数习语来解决这个问题(参见 where to place default value parameter in variable-length function in c++? and default arguments and variadic functions)。但是,我想知道编译器是否只是愚蠢,或者是否存在未实现上述代码示例中的预期行为的真正原因。换句话说,为什么即使我将函数显式实例化为 foo<const char*>(int, const char*),编译器也会报错?就好像显式实例化只是忽略了默认参数的值。为什么?

具有默认值的参数仍然是位置性的。你的例子和

一样
void foo(int i=8, const char * c="hello world")
{
    std::cout << "Default param \t= " << i << "\n";
    std::cout << "Additional param \t= " << c << "\n";
}

int main()
{
    foo();                  // 8 "hello world"
    foo(1, "str1");         // 1 "str1"
    foo("str3");            // ERROR: parameter mismatch

    return 0;
}

这行不通的原因与它行不通的原因相同:

void f(int = 0, const char*);

int main() {
    f("test")
}

如果您阅读错误,您会发现编译器无法将字符串文字转换为 int。这是真的,第一个参数是一个int,你给它发送了一个字符串文字。

无论是否有默认参数,参数都不能反弹到其他位置。

你引用的标准只是说形成是合法的

template<typename ...Ts>
void foo(int i=8, Ts... args)

虽然调用它时,您仍然必须传递一个 int 作为第一个参数,否则在重载决策期间将不会考虑该函数。当你这样做时

foo("str3");

编译器将查找任何接受 const char*const char(&)[5] 的函数 foo,因为这是唯一的参数。这意味着您的函数被完全忽略,因为它期望第一个参数和 int 或根本没有参数。