类的朋友操作符似乎不参与重载解析 [英] In-class friend operator doesn't seem to participate in overload resolution

查看:106
本文介绍了类的朋友操作符似乎不参与重载解析的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在编写一个CRTP模板,使类基于模板参数为 operator + 提供重载时,我发现一个类中的朋友操作符似乎不参与



下面是:

pre> 枚举类FooValueT {
zero,one,two
};

class Foo {
FooValueT val_;
public:
Foo(FooValueT x):val_(x){};

Foo& operator + =(Foo other){
val_ =(FooValueT)((int)val_ +(int)other.val_);
return * this;
}

//重载Foo + Foo,FooValueT + Foo和Foo + FooValueT
朋友Foo操作符+(Foo lhs,Foo rhs){
Foo ret = lhs;
return ret + = lhs;
}

//显式重载FooValueT + FooValueT
friend Foo operator +(FooValueT lhs,FooValueT rhs){
return(Foo)lhs + ;
}
};

看起来有点过分,但由于 Foo my = FooValueT ::一个+ FooValueT :: zero; 应该是一个有效的表达式,如果没有参数有类类型,它们不会隐式转换,如这个回答到我以前的问题。



尽管所有这些努力,下面的代码不能编译:

  int main int argc,char * argv [])
{
Foo my = FooValueT :: zero;
my + = FooValueT :: one;
my = Foo(FooValueT :: zero)+ FooValueT :: two;
my = FooValueT :: zero + Foo(FooValueT :: two);
my = FooValueT :: zero + FooValueT :: two; // error C2676
return 0;
}

错误讯息是:

 错误C2676:binary'+':'FooValueT'未定义此运算符或转换为预定义运算符可接受的类型

一旦我将操作符完全移出类,或者将其声明为朋友,但在类外定义它,此问题解决。当 Foo 是要从中派生的模板类时,两者似乎都不可行。



就像我知道的,上面的类的朋友定义 operator +(ValueT,ValueT)应该创建一个自由函数,就像这个定义:

  class Foo {
/ *所有你之前看到的东西* /
friend Foo operator +(FooValueT lhs,FooValueT rhs);
};

Foo操作符+(FooValueT lhs,FooValueT rhs){
return(Foo)lhs +(Foo)rhs;
}

我在哪里出错?

解决方案

n3376 11.3 / 6 -7


一个函数可以在一个类if和
的好友声明中定义,本地类(9.8),函数名是
,无限定,函数有命名空间范围。



这样的函数是隐式内联的。
类中定义的友元函数在定义它的类的(词法)范围中。在类外定义的
friend函数不是(3.4.1)。


在类范围中,当您尝试调用此运算符时,ADL不会尝试在类中查找运算符,因为两个参数都不具有此类的类型。只是写免费的函数(或朋友与声明不在类)。



似乎你不能做这样的事情,在类中声明的友元函数的问题是函数将在类范围,但你不能声明这个函数是自由的朋友函数,因为编译器不能推断返回类型参数。


While writing a CRTP template that enables classes to provide overloads for operator+ based on template arguments, I found that an in-class friend operator doesn't seem to participate in overload resolution if none of it's arguments is of the type of the class it was defined in.

Boiled down:

enum class FooValueT{
    zero, one, two
};

class Foo{
    FooValueT val_;
public:
    Foo(FooValueT x) : val_(x){};

    Foo& operator+=(Foo other){
        val_ = (FooValueT)((int)val_ + (int)other.val_);
        return *this;
    }

    //overload for Foo+Foo, FooValueT+Foo and Foo+FooValueT
    friend Foo operator+(Foo lhs, Foo rhs){
        Foo ret = lhs;
        return ret += lhs;
    }

    //explicit overload for FooValueT+FooValueT
    friend Foo operator+(FooValueT lhs, FooValueT rhs){
        return (Foo)lhs + (Foo)rhs;
    }
};

Looks a bit excessive, but is necessary since Foo my = FooValueT::one + FooValueT::zero; should be a valid expression and if none of the arguments has class-type, they are not implicitly converted, as explained in this answer to a previous question of mine.

Despite all this effort, the following code does not compile:

int main(int argc, char* argv[])
{
    Foo my = FooValueT::zero;
    my += FooValueT::one;
    my = Foo(FooValueT::zero) + FooValueT::two;
    my = FooValueT::zero + Foo(FooValueT::two);
    my = FooValueT::zero + FooValueT::two; //error C2676
    return 0;
}

The error message is:

error C2676: binary '+' : 'FooValueT' does not define this operator or a conversion to a type acceptable to the predefined operator

This problem resolves once I either move the operator out of the class completely, or declare it as a friend but define it outside the class. Neither of both seem to be viable options when Foo is a template class that is to be derived from.

As far as I know, the above in-class friend definition of operator+(ValueT,ValueT) should create a free function, just as this definition would:

class Foo{
/*All the stuff you saw previously*/
    friend Foo operator+(FooValueT lhs, FooValueT rhs);
};

Foo operator+(FooValueT lhs, FooValueT rhs){
    return (Foo)lhs + (Foo)rhs;
}

Where am I going wrong here? Does in-class friend definition of functions change the rules of overload resolution compared to regular free friend functions?

解决方案

n3376 11.3/6-7

A function can be defined in a friend declaration of a class if and only if the class is a non-local class (9.8), the function name is unqualified, and the function has namespace scope.

Such a function is implicitly inline. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not (3.4.1).

In your case operator is in class-scope and when you are trying to call this operator, ADL will not try to find operator in class, since neither argument has type of this class. Just write free function (or friend with declaration not in class).

Seems like you cannot do something like this, problem with declaration of friend function in class is that function will be in class-scope, but you cannot declare this function to be free friend function, since compiler cannot infer return-type parameter.

这篇关于类的朋友操作符似乎不参与重载解析的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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