运算符>>(,)过载以令人惊讶的方式表现 [英] operator>>(,) overload behaving in a surprising way

查看:129
本文介绍了运算符>>(,)过载以令人惊讶的方式表现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,也许这并不奇怪。 Stackoverflow有很多问题和贡献的那一点。



这里是C ++标准的一个提取(实际上是一个c ++ 14草案,但我认为这段话是相同的当前C ++ 11标准):


运算符函数应为非静态成员函数或非成员函数有
至少一个参数,其类型是类,对类的引用,枚举或对
枚举的引用。不能更改运算符的操作数的优先级,分组或数目。
通过定义实现这些运算符的运算符函数,可以为
特定的类和枚举类型更改为每个类型预定义的operators =,(unary)&和,(comma)的含义。 Operator
函数以与其他基类函数相同的方式继承。


因此,根据我的理解,合法地具有1个类型类型和一个非类型类型作为运算符>>(,)的参数。标准不说第一个或第二个参数。



这里有一个令我惊奇的代码片段:

  int operator>> (int v,std :: function< int(int)> transformer)
{
int v1 = transformer
DGS :: CLogger :: GetLogger() - > Log< int>(& IntFormatter,v1);
return v1;
}
static int DoItLoggedAndCompact(int value)
{
int x = operator>>(operator>>(value,DoIt),AnotherIntCalculation); //编译和工作!
return x;
//下面这行代码(用clang ++):
//错误:二进制表达式的操作数无效('int'和'int(*)(int)')
// return值>> DoIt>>另一个计算; :
}

请注意,函数指针不是类类型是一个正确的声明,不是一个全面的答案。如在重写代码中以 int x = ... 开头和操作符>>第二个参数的定义看到的,函数指针被静默转换为std ::函数。



我在标准的任何地方找不到这两个(据称)同义词形式的转换规则不同的段落。



所以,这是一个编译器错误,社区广泛的C ++规范的过度解释或...我们在这里看到的吗?

一个函数指针不是类类型

解决方案



第13.6节中有以下注释:



< blockquote>

运算符重载解析仅在操作数表达式最初具有类
或枚举类型


规范规则在13.3.1.2(强调我):


如果表达式中的操作符的操作数没有类或枚举,假设操作符是一个内置的操作符,并根据第5条解释。



如果任一操作数的类型是类或枚举,可能会声明实现此运算符的用户定义的运算符函数,或者可能需要进行用户定义的转换,以将操作数转换为适合内置运算符的类型。在这种情况下,过载分辨率用于确定要调用哪个算子函数或内置算子来实现算子。因此,运算符符号首先转换为表11中概述的等效函数调用符号


只有当其中一个操作数是类类型时,表单才是同义的。由于没有人在这里,所以不会重写为 operator>>()


Well, maybe it is not so surprising. Stackoverflow has a lot of questions and contributions to that point. Only they are not EXACTLY to the point.

Here an extract from the C++ standard (in fact a c++14 draft, but I assume the passage is the same in current C++11 standard):

An operator function shall either be a non-static member function or be a non-member function that has at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration. It is not possible to change the precedence, grouping, or number of operands of operators. 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. Operator functions are inherited in the same manner as other base class functions.

Thus, to my understanding, it is perfectly legal to have 1 class type and one non-class type as parameters to operator>>(,). The standard does not say "The first" or "The second" parameter. Just "One" of them must be a class type.

Here a code snippet which surprises me:

int operator>> ( int v, std::function<int(int)> transformer )
{
    int v1 = transformer(v);
    DGS::CLogger::GetLogger()->Log<int>(&IntFormatter, v1 );
    return v1;
}
static int DoItLoggedAndCompact( int value )
{
    int x = operator>>( operator>>(value, DoIt) , AnotherIntCalculation ); // compiles and works!
    return x;
// The following line produces (with clang++):
// error: invalid operands to binary expression ('int' and 'int (*)(int)')
//      return value >> DoIt >> AnotherIntCalculation; : 
}

Please note that "A function pointer is not a class type", while being a correct statement, is not a comprehensive answer. As you see in the rewritten code starting with int x = ... and the definition of operator>> second parameter, the function pointer is silently converted to a std::function.

I cannot find anywhere in the standard a passage which states, that the conversion rules for those two (allegedly) synonymous forms differ.

So, is this a compiler bug, a community wide over-interpretation of the C++ specification or...something else we see here? Or simply some stupid oversight on my part?

解决方案

But "A function pointer is not a class type" is the correct answer.

There's the following note in clause 13.6:

operator overload resolution occurs only when an operand expression originally has class or enumeration type

The normative rule is in 13.3.1.2 (emphasis mine):

If no operand of an operator in an expression has a type that is a class or an enumeration, the operator is assumed to be a built-in operator and interpreted according to Clause 5.

If either operand has a type that is a class or an enumeration, a user-defined operator function might be declared that implements this operator or a user-defined conversion can be necessary to convert the operand to a type that is appropriate for a built-in operator. In this case, overload resolution is used to determine which operator function or built-in operator is to be invoked to implement the operator. Therefore, the operator notation is first transformed to the equivalent function-call notation as summarized in Table 11.

The forms are synonymous only when one of the operands is a class type. Since neither one is here, the rewrite as operator>>() doesn't occur.

这篇关于运算符&gt;&gt;(,)过载以令人惊讶的方式表现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆