是否可以将一组给定的运算符简化为任意一组 类?

Is it possible to streamline a given set of operators to any arbitrary set of classes?

考虑以下一组 classes 及其运算符的关系:我们可以用两种不同的方式实现它们。第一个运算符在 class 中定义,而后者在 class...

之外定义
template<typename T>
struct A {
    T value;

    T& operator+(const A<T>& other) { return value + other.value; }
    // other operators
}; 

temlate<typename T>
struct B {
   T value;
   
   T& operator+(const B<T>& other) { return value + other.value; }
};

// Or...
template<typename T>
struct A {
    T value;
};
template<typename T>
T& operator+(const A<T>& lhs, const A<T>& rhs) { return lhs.value + rhs.value; }
// ... other operators

template<typename T>
struct B {
    T value;
};
template<typename T>
T& operator+(const B<T>& lhs, const B<T>& rhs) { return lhs.value + rhs.value; }  
// ... other operators

在 C++ 中有什么方法可以使单个 class 或运算符结构到可以简单地在任意 class C 中声明或定义它们的位置而不必为每个 class 多次编写相同的运算符?我假设运算符将具有相同的行为,并且 属性 对于每个定义它们的不同 class 考虑到它们都将遵循相同的模式。

例如:

template<typename T, class Obj>
struct my_operators {
    // define them here 
};

// Then
template<typename T>
struct A {
    T value;
    my_operators ops;
};

template<typename T>
struct B {
    T value;
    my_operators ops;
};

请记住,我将此限制为 C++17,因为我无法使用任何 C++20 功能,例如概念...如果可能,我将使用哪种方法或构造能够使用,它的结构和正确的语法是什么样的?如果这是可能的,那么我将能够编写一次运算符,只要使用 classes 的模式匹配就可以重用它们,而不必为每个人编写这些运算符 class ...

使用 CRTP 继承怎么样?

#include <iostream>

template <typename T>
struct base_op
 {
   auto operator+ (T const & o) const
    { return static_cast<T&>(*this).value + o.value; }
 };

template<typename T>
struct A : public base_op<A<T>>
 { T value; }; 

template<typename T>
struct B : public base_op<B<T>>
 { T value; }; 

int main()
 {
   A<int>   a1, a2;
   B<long>  b1, b2;

   a1.value = 1;
   a2.value = 2;

   std::cout << a1+a2 << std::endl;

   b1.value = 3l;
   b2.value = 5l;

   std::cout << b1+b2 << std::endl;
 }

显然这仅适用于具有 value 成员的模板 classes。

对于“class”之外的版本,base_op变为

template <typename T>
struct base_op
 {
   friend auto operator+ (T const & t1, T const & t2)
    { return t1.value + t2.value; }
 };

-- 编辑--

OP 询问

now I'm struggling to write their equivalent +=, -=, *=, /= operators within this same context... Any suggestions?

有点复杂,因为它们必须 return 对派生对象的引用...我想(例如)operator+=(),在 base_op 中,可能是一些东西作为

T & operator+= (T const & o)
 {
   static_cast<T&>(*this).value += o.value;

   return static_cast<T&>(*this);
 }

采用用户 max66 使用 CRTP 提供的答案,并在我的答案的评论部分借用用户 SamVarshavchik 提供的 transparent comparators 的概念,我能够采用它们并得出结论使用此实现设计:

template<class T>
struct single_member_ops {
    friend auto operator+(T const & lhs, T const & rhs) 
    { return lhs.value + rhs.value; }
    friend auto operator-(T const & lhs, T const & rhs) 
    { return lhs.value - rhs.value; }

    template<typename U>
    friend auto operator+(T const& lhs, const U& rhs) 
    { return lhs.value + rhs.value; }

    template<typename U>
    friend auto operator-(T const& lhs, const U& rhs )
    { return lhs.value - rhs.value;}    
};

template<typename T>
struct A : public single_member_ops<A<T>>{
    T value;    
    A() = default;
    explicit A(T in) : value{in} {}
    explicit A(A<T>& in) : value{in.value} {}
    auto& operator=(const T& rhs) { return value = rhs; }
};

template<typename T>
struct B : public single_member_ops<B<T>> {
    T value;
    B() = default;
    explicit B(T in) : value{in} {}
    explicit B(B<T>& in) : value{in.value} {}
    auto& operator=(const T& rhs) { return value = rhs; }
};

int main() {
    A<int> a1(4);
    A<int> a2;
    A<int> a3{0};
    a2 = 6;
    a3 = a1 + a2; 

    B<double> b1(3.4);
    B<double> b2(4.5);

    auto x = a1 + b2;
    auto y1 = a2 - b2;
    auto y2 = b2 - a1;

    return x;
}

您可以看到,这将在 Compiler Explorer 上的示例中进行编译。

额外的 templated operator 允许不同的类型:A<T>B<U> 使用运算符,即使 TU 对于两个 AB 提供 TU 之间的默认转换。但是,用户必须注意截断、上溢和下溢以及缩小转换,具体取决于他们对 TU 的选择。