0

由于8.3.6 ([dcl.fct.default])/4

在给定的函数声明中,带有默认实参的形参后面的每个形参都应具有在此声明或先前声明中提供的默认实参,或者应为函数形参包。

以下应编译:

#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"(type const char*) 转换为 type int

我知道可以通过函数重载或使用命名参数习语来解决这个问题(参见在哪里将默认值参数放置在 c++ 中的可变长度函数中?以及默认参数和可变参数函数)。但是,我想知道编译器是否只是愚蠢的,或者是否有真正的原因导致上面代码示例中的预期行为没有实现。换句话说,即使我将函数显式实例化为,为什么编译器会抱怨foo<const char*>(int, const char*)?就好像显式实例化只是忽略了默认参数的值。为什么?

4

3 回答 3

5

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

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

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

foo("str3");

编译器将寻找任何foo采用 aconst char*或 a 的函数,const char(&)[5]因为这是唯一的参数。这意味着您的函数被完全忽略,因为它需要int第一个参数或根本没有参数。

于 2020-01-10T16:30:34.700 回答
5

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

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;
}
于 2020-01-10T16:28:01.800 回答
3

这不起作用的原因与它不起作用的原因相同:

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

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

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

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

于 2020-01-10T16:28:25.757 回答