sky*_*ack 18 c++ operator-overloading void comma-operator language-lawyer
考虑以下结构:
struct S {};
Run Code Online (Sandbox Code Playgroud)
在C++ 14中,以下定义是有效的:
constexpr auto f() { return S{}, 'c'; }
Run Code Online (Sandbox Code Playgroud)
以及以下一个:
constexpr auto f() { return S{}, void(); }
Run Code Online (Sandbox Code Playgroud)
现在,请考虑以下涉及两个定义中的第一个的工作代码段:
#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, "!");
}
Run Code Online (Sandbox Code Playgroud)
说来不是技术上的,逗号运算符的重载拦截了这对,S{}, 'c'并返回一个整数,正如在main函数中正确验证的那样.
现在,假设我想对第二个定义做同样的事情f:
constexpr auto f() { return S{}, void(); }
Run Code Online (Sandbox Code Playgroud)
在这种情况下,逗号运算符应截取表单S{}, void().
以下定义都不起作用(出于显而易见的原因):
constexpr int operator,(S, void) { return 42; }
Run Code Online (Sandbox Code Playgroud)
也不是下面的那个(在前一个案例中会起作用):
template<typename T> constexpr int operator,(S, T &&) { return 42; }
Run Code Online (Sandbox Code Playgroud)
有没有办法重载逗号运算符以便处理S{}, void()?
是否缺少标准,因为它允许以这种方式使用逗号运算符,但是不会让你有机会重载相同的运算符(即使标准提到S允许重载函数)?
注意:这个问题是为了好奇而制作的.请避免评论,如不这样做或不是好习惯.我不打算在生产环境中这样做.谢谢.
Bau*_*gen 24
相关条款是N4140中的13.3.1.2/9 [over.match.oper]:
如果操作员是操作员
,,一元操作员&或操作员->,并且没有可行的功能,则假定操作员是内置操作员并根据第5章解释.
因为void()永远不是一个有效的函数参数(见5.2.2/7 [expr.call]),所以从来没有一个可行的函数,因此,将使用内置函数.
所以不,你想做的事情是不可能的.
实际上,像这样编写迭代器循环
for(...; ++it1, (void)++it2)
Run Code Online (Sandbox Code Playgroud)
是一种标准方法,,通过强制使用内置运算符,来防止用户通过重载迭代器类型来破坏代码.(请注意,我并不是说您需要在日常代码中执行此操作.这在很大程度上取决于其实际使用情况.这是偏执狂的标准库级别.)
关于您链接的标准条款:
通过定义实现这些运算符的运算符函数,可以针对特定类和枚举类型更改为每种类型预定义的operator =,(一元)&和(逗号)的含义.
但是,无法定义这样的函数,因为如上所述,void()它永远不是有效的函数参数.
现在,无论这是否是标准中的疏忽/问题,都值得商榷.