void()、逗号运算符 (operator,) 和不可能的 (?) 重载

The void(), the comma operator (operator,) and the impossible (?) overloading

考虑以下结构:

struct S {};

在 C++14 中,以下定义有效:

constexpr auto f() { return S{}, 'c'; }

以及以下一项:

constexpr auto f() { return S{}, void(); }

现在,考虑以下涉及两个定义中的第一个的工作片段:

#include<type_traits>

struct S {};

constexpr int operator,(S, char) { return 42; }
constexpr auto f() { return S{}, 'c'; }

int main() {
    constexpr int i{f()};
    static_assert(i == 42, "!");
    static_assert(std::is_same<decltype(f()), int>::value, "!");
}

从技术上讲,逗号运算符 的重载截取 这对 S{}, 'c' 和 returns 一个整数,如 [= 中正确验证的那样18=]函数。

现在,假设我想对 f 的第二个定义做同样的事情:

constexpr auto f() { return S{}, void(); }

在这种情况下,逗号运算符应该截取形式S{}, void()
以下定义均无效(原因很明显):

constexpr int operator,(S, void) { return 42; }

也不是下面的那个(在前一种情况下会起作用):

template<typename T> constexpr int operator,(S, T &&) { return 42; }

有没有办法重载逗号运算符来处理S{}, void()
标准中是否缺少其他方面,因为它允许以这种方式使用逗号运算符,但不会让您有机会重载相同的运算符(即使 the standard mentions that overloaded functions involving S are allowed)?


:本题为好奇而生。请避免评论不要那样做这不是好的做法。我不打算在生产环境中这样做。谢谢。

与此相关的条款是 N4140 中的 13.3.1.2/9 [over.match.oper]:

If the operator is the operator ,, the unary operator &, or the operator ->, and there are no viable functions, then the operator is assumed to be the built-in operator and interpreted according to Clause 5.

因为 void() 永远不是一个有效的函数参数(见 5.2.2/7 [expr.call]),所以从来没有一个可行的函数,因此内置 ,将被使用。

所以不,你想做的事是不可能的。

其实就是这样写迭代器循环

for(...; ++it1, (void)++it2)

是防止用户通过强制使用内置运算符 , 为其迭代器类型重载 , 来破坏您的代码的标准方法。 (请注意,我并不是说你需要在日常代码中这样做。这在很大程度上取决于它的实际使用。这是偏执狂的标准库级别。)


关于您链接的标准条款:

The meaning of the operators =, (unary) &, and , (comma), predefined for each type, can be changed for specific class and enumeration types by defining operator functions that implement these operators.

但是无法定义这样的函数,因为正如我上面所说,void() 永远不是有效的函数参数。

现在这是否是标准中的 oversight/problem 尚待讨论。