我非常喜欢使用特殊结构和指定的初始化程序来模拟函数的命名参数。
struct Args {
int a;
int b;
};
int f(Args a) {
return a.a + a.b;
}
int g() {
return f({.a = 1, .b = 2}); // Works! That's what I want.
return f({1, 2}); // Also works. I want to forbid this, though.
}
但是,这些结构仍然可以通过位置初始化器列表进行初始化。也就是说,你仍然可以呼叫f({1, 2})
。
我想禁止这种情况,并强制调用方也在调用站点显式命名参数。我如何在C++20中做到这一点?
最好的方法就是代码评审。告诉人们使用指定的初始化程序。指定的初始化程序非常棒,人们喜欢使用它们。这实际上是一个社会问题,而不是技术问题。
如果你真的想推动一下,你可以先加入一些非常糟糕的数据成员,比如:
class Args {
struct Key { explicit Key() = default; };
struct StopIt { StopIt(Key) { } };
public:
StopIt asdfjkhasdkljfhasdf = Key();
int a;
int b;
};
Args
仍然是一个聚合,我们只是有这个额外的前导数据成员,拼写了我刚敲键盘时出现的任何内容。它有一个默认的成员初始值设定项,但该初始值设定器对Args
是私有的,只有Args
知道如何构造它
因此,用户无法†正确地为该特定成员提供初始值设定项,他们必须依靠默认的成员初始值设定器来正确地初始化它。由于它首先进行,所以它们必须依赖于指定的初始化,以便能够初始化任何其他成员。
但是。。。这写起来有点傻?只需告诉人们使用指定的初始化即可。
†从技术上讲,在这种情况下,他们可以编写f({Args().asdfjkhasdkljfhasdf, 1, 2})
,但在这一点上,我们似乎在走向荒谬或怨恨。