c++ - 使用继承的成员运算符而不是免费的成员运算符

标签 c++ inheritance operator-overloading overload-resolution

假设在命名空间 ns 的某处定义了一个自由的 operator*:

namespace ns {
    struct Dummy {};

    template <typename T>
    Dummy operator*(T&&) {
        return {};
    }
}

在不同的地方,同一命名空间中有一个基类,它定义了成员operator*:

namespace ns {
    template <typename T>
    struct Base {
        T x;

        T& operator*() { 
            return x;
        }
    };
}

还有很多由它派生的类型。它们的行为相同,但必须不同,因为其他地方的模板需要专门针对它们:

namespace ns {
    template <typename T>
    struct DerivedA : Base<T> {};

    template <typename T>
    struct DerivedB : Base<T> {};

    template <typename T>
    struct DerivedC : Base<T> {};

    // etc
}

当我尝试在派生类上使用 operator* 时:

ns::DerivedA<int> d;
*d = 42;

GCC 对我大喊“傻瓜!你不能将 int 分配给 Dummy!”,这显然意味着 free operator* 是用于代替基类中的成员一。

我完全无法控制自由运算符,并且无法将派生类移动到不同的命名空间。

如何解决此问题而不在每个派生类中重复 operator*

最佳答案

简短的回答,你可以这样做:

template <typename T>
struct DerivedA : Base<T> {
    using Base<T>::operator*;
};

长答案:为了弄清楚要调用什么*d,我们必须确定所有可行的函数(第13.3.2节):

From the set of candidate functions constructed for a given context (13.3.1), a set of viable functions is chosen, from which the best function will be selected by comparing argument conversion sequences for the best fit (13.3.3). The selection of viable functions considers relationships between arguments and function parameters other than the ranking of conversion sequences.

有两个:

template <typename T>
Dummy operator*(T&& );

T& Base::operator*();

为了确定选择哪一个,我们必须确定哪个“隐式转换序列”(§13.3.3.1) 更好:

An implicit conversion sequence is a sequence of conversions used to convert an argument in a function call to the type of the corresponding parameter of the function being called.

第一个选项是“精确匹配”,第二个重载选项是(§13.3.3.1.6):

When the parameter has a class type and the argument expression has a derived class type, the implicit conversion sequence is a derived-to-base Conversion from the derived class to the base class. [ Note: There is no such standard conversion; this derived-to-base Conversion exists only in the description of implicit conversion sequences. —end note ] A derived-to-base Conversion has Conversion rank

转换序列的排名为(§13.3.3.1.1.3):

Each conversion in Table 12 also has an associated rank (Exact Match, Promotion, or Conversion). These are used to rank standard conversion sequences (13.3.3.2). The rank of a conversion sequence is determined by considering the rank of each conversion in the sequence and the rank of any reference binding (13.3.3.1.4). If any of those has Conversion rank, the sequence has Conversion rank; otherwise, if any of those has Promotion rank, the sequence has Promotion rank; otherwise, the sequence has Exact Match rank.

我不知道如何在这里插入表格。但基本上我们有一个“精确匹配”(调用 Dummy operator*(T&&))和一个“转换”(调用 T& Base::operator*),因此“精确匹配”是“最佳可行功能”。和(§13.3.3.2):

If there is exactly one viable function that is a better function than all other viable functions, then it is the one selected by overload resolution

这就是为什么首选虚拟运算符*(T&& )

现在,为什么我的提案有效?在这种情况下,我们的两个选择是:

template <typename T>
Dummy operator*(T&& );

T& DerivedA<int>::operator*();

因此,我们有两个“精确匹配”候选者 - 尽管其中之一是通过模板实现的,并且选择更好的可行函数的标准之一是(§13.3.3.1):

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if ...

  • F1 is a non-template function and F2 is a function template specialization

因此,在本例中,我们选择 DerivedA::operator*。这就是你想要的。

关于c++ - 使用继承的成员运算符而不是免费的成员运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27078793/

相关文章:

c++ - LLVM CreateFCmpONE 等效于整数

c++ - 我可以使用 OpenCL 分配设备内存并使用指向 CUDA 内存的指针吗?

c++ - C++ 中枚举数的作用域

c++ - 我可以对 2 个外观相似的类使用类型转换运算符吗?

c++ - 运算符重载 (C++)

c++ - 将 lambda 放在静态初始化列表中并通过引用捕获是否安全?

c# - 继承自网络客户端类

c++ - 将默认构造函数添加到基类会更改派生类型的 sizeof()

python - Python 中的基本多态性混淆

c++ - 在 C++ 中重载 -> 运算符