静态运算符 () 和 [] (C++23)

Pap*_*ter 7 c++ operator-overloading language-lawyer c++23

operator ()引入了和的静态版本operator []:

\n
#include <iostream>\n#include <format>\n\nstruct S\n{\n    static int operator()(int a, int b) { return a + b; }\n    static int operator[](int a, int b) { return a - b; }\n};\n\nint main()\n{\n    std::print("({})[{}]", S{}(1, 0), S{}[3, 1]); // (1)[2]\n//                          ^^         ^^ <-- Create temporary instances of \'S\'?!\n    std::print("({})[{}]", S()(2, 1), S()[5, 1]); // (3)[4]\n//                          ^^         ^^ <-- Create temporary instances of \'S\'?!\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

令我震惊的是,为了调用静态版本的运算符()和[]需要类的实例;我期望能够从类型中调用两个运算符(作为其他静态成员),但它的格式不正确:

\n
//            type --> v        v <-- type\nstd::print("({})[{}]", S(1, 0), S[3, 1]); // (1)[2]\n// static operator() -> \\____/   \\____/ <- static operator[]\n
Run Code Online (Sandbox Code Playgroud)\n

但S(1, 0)看起来像一个构造函数哈哈,愚蠢的我!,如果类型S碰巧有一个S(int, int)构造函数\xe2\x80\xa6,则会导致歧义,但是那又如何呢?S[3, 1]?这不会与任何类内实体发生冲突。

\n

好吧,也许type(...)和type[...]是有问题的,但是使用作用域运算符怎么样?不幸的是,这也是错误的:

\n
//            type --> v          v <-- type\nstd::print("({})[{}]", S::(1, 0), S::[3, 1]); // (1)[2]\n//   static operator() -> \\____/     \\____/ <- static operator[]\n
Run Code Online (Sandbox Code Playgroud)\n
\n

我一直在阅读p1169r4和p2589r0论文,但我找不到任何“强制”实例化类型以调用静态运算符的理由(),[]也找不到为什么不允许使用type::(...)or形式。type::[...]

\n

我错过了什么吗?

\n

Bar*_*rry 13

静态的动机operator(),然后为了一致性,静态的动机operator[]是允许使这些运算符静态。允许s(a, b)不必需要额外的对象参数,而只是希望它能够被优化掉。

但该函数的名称是operator()- 它不是()。S::(a, b)不是今天称呼该接线员的方式,而是S::operator()(a, b). 允许运算符使用这种不同的调用语法是完全不同的功能。

您引用的提案没有理由“强迫”任何东西,因为它们没有强迫任何东西 - 这是现有的语言。

它看起来也不像是一个超级激励功能,因为在您有静态调用或静态下标运算符的情况下,您可能没有状态(否则运算符可能不会是静态的),所以S::(a, b)不是t 任何短于S{}(a, b).

但如果您想以这种方式使用它,您也可以创建一个以下类型的全局对象:

struct S
{
    static int operator()(int a, int b) { return a + b; }
    static int operator[](int a, int b) { return a - b; }
};

inline S S;
Run Code Online (Sandbox Code Playgroud)

这允许您使用最初想要的语法:

std::print("({})[{}]", S(1, 0), S[3, 1]); // (1)[2]
// static operator() -> \____/   \____/ <- static operator[]
Run Code Online (Sandbox Code Playgroud)

  • 嗯,很明显 `S::(a, b)` 并不比 `S{}(a, b)` 短,但在前者中,我们明确地在 `S` 范围内调用了一些东西 **没有* * 实例化 `S` 并在稍后创建一个实例,考虑到我们调用的是静态成员,这很奇怪。我的意思是“S::(a, b)”与“S{}(a, b)”具有非常不同的含义。 (2认同)