为什么默认参数不能与参数包一起使用?
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
或根本没有参数。
因为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
或根本没有参数。