考虑以下结构:
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'
并返回一个整数,正如main
函数中正确验证的那样。
现在,假设我想对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)?< / p>
注意:这个问题是为了好奇而制作的。请避免像那样做或不是好习惯这样的评论。我不打算在生产环境中这样做。谢谢。
答案 0 :(得分:23)
相关条款是N4140中的13.3.1.2/9 [over.match.oper]:
如果运算符是运算符
,
,一元运算符&
或运算符->
,并且没有可行的函数, 然后假定操作符是内置操作符并根据第5章进行解释。
由于void()
永远不是有效的函数参数(参见5.2.2 / 7 [expr.call]),因此永远不会有可行的函数,因此将使用内置的,
。
所以不,你想做的事情是不可能的。
实际上,像这样编写迭代器循环
for(...; ++it1, (void)++it2)
是一种标准方法,可以通过强制使用内置运算符,
来阻止用户通过为其迭代器类型重载,
来破坏代码。 (请注意,我并不是说您需要在日常代码中执行此操作。这在很大程度上取决于其实际使用情况。这是偏执狂的标准库级别。)
关于您链接的标准条款:
通过定义实现这些运算符的运算符函数,可以为特定类和枚举类型更改为每种类型预定义的operator =,(一元)&amp;和(逗号)的含义
但是这样的函数是无法定义的,因为正如我上面所说,void()
永远不是一个有效的函数参数。
现在,这是否是标准中的疏忽/问题是值得商榷的。