简体   繁体   中英

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM