交换运算符重载+ 2个不同的对象

时间:2010-09-21 21:22:27

标签: c++ operator-overloading operator-keyword commutativity

我有两个代表矩阵的类:
1. RegularMatrix - O(n ^ 2)表示
2. SparseMatrix - 一个表示为链表(没有零)的矩阵。

我想说:

RegularMatrix a;
SparseMatrix b;

我希望能够做到:

a+b;

还有:

b+a;

所以我重载了+运算符。我的问题是,既然我希望加法是可交换的(a + b = b + a),我是否需要实现2个过载,每种情况一个?

RegularMatrix operator+(const RegualarMatrix &, const SparseMatrix &);
RegularMatrix operator+(const SparseMatrix & ,const RegualarMatrix &);

还是编译器自己决定的一般形式?

谢谢

3 个答案:

答案 0 :(得分:8)

是的,你需要两个版本。但是如果操作真的是可交换的话,你可以把它转发到另一个

RegularMatrix operator+(const SparseMatrix &a, const RegualarMatrix &b) {
    return b + a;
}

答案 1 :(得分:1)

两个版本都是必需的,只需在首次过载后写入:

RegularMatrix operator+(const SparseMatrix &a, const RegualarMatrix &b)
{
    return operator+(b,a);
}

或更简单的版本:

RegularMatrix operator+(const SparseMatrix &a, const RegualarMatrix &b)
{
    return b + a;
}

答案 2 :(得分:0)

除非您有大量带有复杂签名的运算符,所有这些运算符都需要为交换行为复制,否则我只会使用已接受答案中的解决方案。但是,如果你真的讨厌重复你的代码或者只是为了它而想让它工作:

#include <iostream>    // std::cout
#include <utility>     // std::pair
#include <type_traits> // std::remove_cvref_t
#include <concepts>    // std::same_as

// These two utilities will be used for all commutative functions:

template <typename T, typename U, typename V, typename W>
concept commutative =
    (std::same_as<std::remove_cvref_t<T>, V> && std::same_as<std::remove_cvref_t<U>, W>) ||
    (std::same_as<std::remove_cvref_t<U>, V> && std::same_as<std::remove_cvref_t<T>, W>);

template <typename V, typename W, typename T, typename U>
requires commutative<T, U, V, W>
constexpr decltype(auto) order (T && a, U && b) {
    if constexpr (std::same_as<std::remove_cvref_t<T>, V>)
        return std::pair{std::forward<T>(a), std::forward<U>(b)};
    else
        return std::pair{std::forward<U>(b), std::forward<T>(a)};
}

// Here goes the use-case:

struct A {
    int aval;
};

struct B {
    int bval;
};

// This template declaration allows two instantiations:
// (A const &, B const &) and (B const &, A const &)
template <typename T, commutative<T, A, B> U>
A operator + (T const & first, U const & second) {
    // But now we need to find out which is which:
    auto const & [a, b] = order<A, B>(first, second);
    return {.aval = a.aval + b.bval};
}

// Just to test it:
int main () {
    A a = {.aval = 1};
    B b = {.bval = 2};

    A c = a + b;
    A d = b + a;

    std::cout << c.aval << '\n';
    std::cout << d.aval << '\n';
}

如果 template <typename T, commutative<T, A, B> U>auto const & [a, b] = order<A, B>(first, second); 比用 return b + a; 为您的场景重复整个定义更少的样板代码,那么我想它可能会有用。