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

问题描述 投票:0回答:3

由于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"(类型const char*)转换为类型int

我知道可以通过函数重载或使用命名的参数惯用法来解决此问题(请参阅where to place default value parameter in variable-length function in c++?default arguments and variadic functions)。但是,我想知道编译器是不是只是愚蠢的,或者是否有真正的原因导致上述代码示例中的预期行为没有实现。换句话说,即使我将函数显式实例化为foo<const char*>(int, const char*),为什么编译器也会抱怨?就像显式实例化只是忽略默认参数的值一样。为什么?

c++ variadic-templates default-value function-templates explicit-instantiation
3个回答
2
投票

具有默认值的参数仍处于位置。您的示例与

相同
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();                  // 1 "hello world"
    foo(1, "str1");         // 1 "str1"
    foo("str3");            // ERROR: parameter mismatch

    return 0;
}

1
投票

此功能不起作用的原因相同:

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

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

如果读取错误,您会看到编译器无法将字符串文字转换为int。这是真的,第一个参数是int,并且您向其发送了字符串文字。

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


0
投票

您引用的标准只是说组建是合法的

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

尽管调用它,但仍然必须传递int作为第一个参数,否则在重载解析期间将不考虑该函数。当你做

foo("str3");

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

© www.soinside.com 2019 - 2024. All rights reserved.