In-class friend operator doesn't seem to participate in overload resolution

ⅰ亾dé卋堺 提交于 2019-12-19 19:57:23

问题


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?


回答1:


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.



来源:https://stackoverflow.com/questions/27376365/in-class-friend-operator-doesnt-seem-to-participate-in-overload-resolution

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!