gpt4 book ai didi

c++ - 参数列表中任意点的默认参数是否可能?

转载 作者:行者123 更新时间:2023-11-30 01:26:39 26 4
gpt4 key购买 nike

希望阅读本文的人了解默认参数:

void setCase (string &str, int form = UPPERCASE)
{
for (char &c : str)
c = (form == UPPERCASE ? c & ~0x20 : c | 0x20); //this bit differentiates english uppercase and lowercase letters
}

int main()
{
string s1 = "HeLlO", s2 = s1, s3 = s1;
setCase (s1, UPPERCASE); //now "HELLO"
setCase (s2, LOWERCASE); //now "hello"
setCase (s3); //now "HELLO" due to default argument
}

使用默认参数的一个缺点是您必须在列表末尾开始默认参数。有时,这涉及将参数重新排列成一个看起来非常笨拙的顺序。为了解决这个问题,必须进行单独的重载。

让我来看一个 Window API 函数,FindWindow ,通过类名、标题或两者找到一个窗口,例如:

HWND WINAPI FindWindow( //returns handle to window
__in_opt LPCTSTR lpClassName, //param equivalent to const TCHAR *, classes are like templates for windows
__in_opt LPCTSTR lpWindowName //the text that appears on the title bar (for normal windows, for things like buttons, it's what text is on the button)
);

为了总结这一点,人们可能希望默认搜索选项是标题。有三种理想的实现方式(假设使用了其他包装技术)。完美的解决方案很可能如下所示:

Window FindWindow (LPCTSTR className = 0, LPCTSTR windowName){...}

第二种解决方案是重载函数的一个版本以仅接受标题,而另一个版本则接受两者。第三种方法是切换参数的顺序。

第二个的主要问题是对于较长的列表,随着列表的增长,重载的空间量可能会变得非常大。第三种方法的主要问题是,任何以前使用过此函数的人都会习惯于首先指定类名。这也适用于常规 C++ 函数。参数往往具有自然顺序。

当然,第一个解决方案的主要问题是它不受 C++ 语言的支持。我的问题是:
future 是否有可能提供这种服务?

例如,编译器能否在需要时自动生成适当的重载?

最佳答案

这不太可能。有很多 极端情况。当前的规则非常简单易学:“所有默认参数必须位于参数列表的末尾。”新规则将是:“除非必须保留向后兼容性,否则省略的默认参数的组合不得有歧义。”更糟糕的是,这甚至不是您可以在定义点测试的规则,因为 C++ 现在甚至不会对重载函数执行此操作。例如,采用以下两个函数定义:

void foo();
void foo(int x = 0);

这些是完全合法的,尽管期望第一个被调用是不合理的:任何看起来像 foo() 的调用都是不明确的。现在考虑一个假设的 C++ 版本,其中默认参数不必放在末尾:

void foo(int x = 0, int y = 0);

调用 foo(1) 有什么作用?好吧,为了向后兼容,它必须调用 foo(1, 0)。这很有趣,因为这个函数没有这样的困难:

void bar(const char* a = 0, int b = 0);

以下是对该函数的一些合法调用:

bar("foo");
bar(1);
bar("foo", 1);
bar();

所以foo函数只生成三个版本:foo()foo(int)foo(int,整数)。但是这个也有两个默认参数,生成四个。 (而且它们不是明确的:foo(0) 是一个模棱两可的调用。)好吧,很好,您可能可以使用标准中的一些复杂语言来解决这个问题。但是现在考虑这个函数:

struct A;
struct B;
A some_A();
B some_B();
void baz(const A& a = some_A(), const B& b = some_B());

现在生成的版本数取决于用户定义类型的转换,这甚至可能在函数的定义 中不可见。在当前版本的 C++ 中,对 baz(B()) 的调用总是会尝试将 B 实例转换为 A,但会失败否则。现在,有人可以合理地期望在第二个参数中传递你的 B 实例,如果你将 baz 的四个重载版本写成 baz( ), baz(const A&), baz(const B&), baz(const A&, const B&)。除非您想破坏现有代码,否则您甚至不能认为默认参数乌托邦世界中的调用 baz(B()) 是模棱两可的。

即使是相对简单的“默认参数被不同类型的非默认参数分隔”的情况,转换也变得有些困惑。例如,这个:

void quux(A* a = nullptr, B* b, C* c = nullptr);

完全明确:可调用为 quux(B*)quux(A*, B*)quux(B*, C*)quux(A*, B*, C*)。除非 A 继承自 BB 继承自 C(反之亦然)。当然,这与重载决策必须面对的问题相同,但到目前为止默认参数已经完全明确,现在我们陷入了微妙的泥潭。

即使你找到了一个让所有人都满意的一致解决方案,也几乎不可能简明扼要地解释,这很可能是一种净损失。

关于c++ - 参数列表中任意点的默认参数是否可能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10022078/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com