是否可以将一组给定的运算符简化为任意一组 类?
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>
使用运算符,即使 T
和 U
对于两个 A
和 B
提供 T
和 U
之间的默认转换。但是,用户必须注意截断、上溢和下溢以及缩小转换,具体取决于他们对 T
和 U
的选择。
考虑以下一组 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>
使用运算符,即使 T
和 U
对于两个 A
和 B
提供 T
和 U
之间的默认转换。但是,用户必须注意截断、上溢和下溢以及缩小转换,具体取决于他们对 T
和 U
的选择。