2016-09-15 143 views
15

考虑以下结构(?):空隙(),逗号运算符(操作员)和不可能超载

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)?


注意:这个问题对我的好奇心起见。请避免像这样的意见不要那样做这是不好的做法。我不打算在生产环境中这样做。谢谢。

+2

这很吸引人疯狂;) –

+0

@JesperJuhl是的,我知道。标准游击队员。我正在探索语言中最隐蔽的角落。 :-) – skypjack

+0

将运算符','改成'+'给出一个“参数可能没有'void'type”错误。 – kennytm

回答

20

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

如果操作者是操作,,一元运算符&,或者操作员->,并且没有可行函数, 则操作被假定为内置的操作者和解释根据条款5.

void()作为从来都不是一个有效的函数的参数(见5.2.2/7 [EXPR .call]),那里ne ver是一个可行的功能,因此将使用内置的,

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

其实,写一个迭代循环这样

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

是通过执行内置运营商,使用重载,他们的迭代器类型,以防止用户破坏你的代码的标准方式。 (请注意,我不是说你需要做这在日常的代码这在很大程度上取决于它的实际使用这是偏执的标准库的水平。)


关于你所连接的标准条款:

运营商=所述的含义,(一元)&,和,(逗号),预定义的每种类型,可以通过定义实现这些运算符操作员功能更改为特定类和枚举类型

但是这样的函数不能被定义,因为如上所述,void()永远不是有效的函数参数。

现在,无论这是否是标准中的疏忽/问题,都有待讨论。

+2

在循环中有趣地使用'(void)'来避免调用重载的逗号。谢谢你的提示! – paulotorrens