C++20:强制使用指定的初始值设定项来模拟命名函数参数

问题描述

我非常喜欢使用临时结构和指定的初始值设定项来模拟函数的命名参数。

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}),但这似乎是我们目前正在寻找的荒谬或恶意。