Оператор друга в классе, кажется, не участвует в разрешении перегрузки

При написании шаблона CRTP, который позволяет классам обеспечивать перегрузки дляoperator+ основываясь на аргументах шаблона, я обнаружил, что оператор друга в классе, по-видимому, не участвует в разрешении перегрузки, если ни один из его аргументов не соответствует типу класса, в котором он был определен.

Сварили:

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;
    }
};

Выглядит немного чрезмерно, но необходимо, так какFoo my = FooValueT::one + 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;
}

Сообщение об ошибке:

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

Эта проблема решается, когда я либо полностью убираю оператор из класса, либо объявляю его другом, но определяю его вне класса. Ни то, ни другое не кажется приемлемым вариантом, когдаFoo является шаблоном класса, который должен быть получен из

Насколько я знаю, приведенное выше определение друга в классеoperator+(ValueT,ValueT) должен создать свободную функцию, так как это определение будет:

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;
}

Куда я здесь не так? Меняет ли определение функций в классе друга правила разрешения перегрузки по сравнению с обычными бесплатными функциями друга?

Ответы на вопрос(1)

Ваш ответ на вопрос