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

时间:2016-09-15 15:19:13

标签: c++ operator-overloading language-lawyer void comma-operator

考虑以下结构:

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>

注意:这个问题是为了好奇而制作的。请避免像那样做不是好习惯这样的评论。我不打算在生产环境中这样做。谢谢。

1 个答案:

答案 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()永远不是一个有效的函数参数。

现在,这是否是标准中的疏忽/问题是值得商榷的。