c++ - 同级友元运算符似乎不参与重载决议

标签 c++ operator-overloading overloading friend

在编写使类能够根据模板参数为 operator+ 提供重载的 CRTP 模板时,我发现类内友元运算符似乎不参与重载决议,如果没有的话arguments 是它在其中定义的类的类型。

归结:

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; 应该是一个有效的表达式,如果没有参数具有类类型,则它们是未隐式转换,如 this answer 中所述回答我之前的一个问题。

尽管付出了所有这些努力,以下代码仍无法编译:

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

我哪里错了?与普通的自由友元函数相比,函数的类内友元定义是否改变了重载决策规则?

最佳答案

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).

在您的情况下,运算符在类范围内,当您尝试调用此运算符时,ADL 不会尝试在类中查找运算符,因为两个参数都没有此类的类型。只需编写自由函数(或声明不在类里面的 friend )。

似乎你不能这样做,在类中声明友元函数的问题是函数将在类范围内,但你不能将此函数声明为自由友元函数,因为编译器无法推断返回类型参数.

关于c++ - 同级友元运算符似乎不参与重载决议,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27376365/

相关文章:

c++ - 跳过/未发生赋值运算符重载

C++ 重载函数和函数模板 - 不同的行为?

c# - DelegateCommand的重载方法

c++ - 如何 std::bind 智能指针返回方法?

c++ - iOS下OpenGL ES 2.0初始化

c++ - CreateFont() 创建的字体规范和大小不正确

c++ - 模板类型推导在 C++ 中不起作用

c++ - 重载 << 运算符时出现未处理的异常

swift - 你能在 Swift 中重载类型转换运算符吗?

c++ - 使用 CRTP 继承