其他分享
首页 > 其他分享> > c – 可以将重载运算符重构为非成员函数中断任何代码吗?

c – 可以将重载运算符重构为非成员函数中断任何代码吗?

作者:互联网

考虑具有重载加法运算符=和的遗留类模板

template<class T>
class X
{
public:
    X() = default;
    /* implicict */ X(T v): val(v) {}

    X<T>& operator+=(X<T> const& rhs)       { val += rhs.val; return *this; }
    X<T>  operator+ (X<T> const& rhs) const { return X<T>(*this) += rhs;    } 

private:
    T val;
};

在代码审查时,观察到可以在=方面实现,那么为什么不使它成为非成员(并且保证左右参数的对称性)?

template<class T>
class X
{
public:
    X() = default;
    /* implicit */ X(T v): val(v) {}

    X<T>& operator+=(X<T> const& rhs)       { val += rhs.val; return *this; }

private:
    T val;
}; 

template<class T>
X<T> operator+(X<T> const& lhs, X<T> const& rhs)
{ 
    return X<T>(lhs) += rhs; 
}

它看起来足够安全,因为所有有效的表达式使用和=保留其原始的语义含义.

问题:运算符从成员函数重构为非成员函数会破坏任何代码吗?

破损的定义(最差到最好)

>新代码将编译在旧方案下无法编译
>旧代码将无法编译在旧方案下编译
>新代码将静默调用另一个运算符(从通过ADL拖入的基类或关联的名称空间)

解决方法:

摘要

答案是,是的,总会有破损.关键因素是函数模板参数推导不考虑隐式转换.我们考虑三种场景,涵盖了重载运算符可以采用的三种语法形式.

这里我们在X< T>中使用隐式构造函数.本身.但即使我们使该构造函数显式化,用户也可以添加到X< T>的命名空间中. C类< T>它包含表单运算符X< T>()const的隐式转换.在这种情况下,下面的情景将继续存在.

非成员友元函数在允许lhs参数隐式转换的意义上打破最少,这些转换不会为类模板的成员函数进行编译.非成员函数模板打破了rhs参数的隐式转换.

类模板的成员函数

template<class T>
class X
{
public:
    /* implicit */ X(T val) { /* bla */ }
//...
    X<T> operator+(X<T> const& rhs) { /* bla */ }
//...
};

这段代码将允许表达式

T t;
X<T> x;
x + t;  // OK, implicit conversion on non-deduced rhs
t + x;  // ERROR, no implicit conversion on deduced this pointer

非会员朋友功能

template<class T>
class X
{
public:
    /* implicit */ X(T val) { /* bla */ }
//...
    friend 
    X<T> operator+(X<T> const& lhs, X<T> const& rhs) { /* bla */ }
//...
};

由于friend函数不是模板,因此不会发生参数推导,并且lhs和rhs参数都考虑隐式转换

T t;
X<T> x;
x + t;  // OK, implicit conversion on rhs
t + x;  // OK, implicit conversion on lhs

非会员功能模板

template<class T>
class X
{
public:
    /* implicit */ X(T val) { /* bla */ }
//...
};

template<class T> 
X<T> operator+(X<T> const& lhs, X<T> const& rhs) { /* bla */ }

在这种情况下,lhs和rhs参数都经过参数推导,并且都没有考虑隐式转换:

T t;
X<T> x;
x + t;  // ERROR, no implicit conversion on rhs
t + x;  // ERROR, no implicit conversion on lhs

标签:c,operator-overloading,implicit-conversion,argument-dependent-lookup,non-member-
来源: https://codeday.me/bug/20191007/1868595.html