c++ 具有多个类型的模板类中的运算符重载

dfuffjeb  于 2023-02-10  发布在  其他
关注(0)|答案(2)|浏览(198)

我正在尝试构建一个模板化的向量类,它可以基于任何算术类型并使用它们进行数学运算。因此,应该允许Vec 3+ Vec 3。以下是我的声明:

template <typename T>
class Vec3 {
private:
    T _x, _y, _z;
public:
    static_assert(std::is_arithmetic_v<T>, "Type must be arithmetic");
    Vec3(T x, T y, T z);
    ~Vec3() = default;
    
    template <typename U, typename V>
    friend Vec3<T> operator+(Vec3<U> lhs, const Vec3<V>& rhs);    
};

我为这个函数写了两个定义(相同的hpp文件,但更进一步),一个是如果所有输入类型都相同,那么输出类型也应该相同,但如果其中一个不同,那么输出取决于:int+double-〉double,double+int -〉double,long+int -〉long,...你懂的。

template <typename T>
Vec3<T> operator+(Vec3<T> lhs, const Vec3<T>& rhs) {
    return Vec3<T>(T x, T y, T z);
}

template <>
Vec3<double> operator+(Vec3<int> lhs, const Vec3<double>& rhs) {
    return Vec3<double>(double x, double y, double z);
}

template <>
Vec3<double> operator+(Vec3<double> lhs, const Vec3<int>& rhs) {
    return Vec3<double>(double x, double y, double z);
}
...

我以为我会为所有允许类型的组合重载运算符+,但是我得到了一个错误:

error: template-id 'operator+><' for 'Color3<double> operator+(Color3<int>, const Color3<double>&)' does not match any template declaration

什么是正确的方法去设置任何数量的类型的可能组合?谢谢。

afdcj2ne

afdcj2ne1#

如果你想让任何两个基于Vec3的实体都能使用operator+,你可以添加一个friend来推导正确的返回类型:Vec3<decltype(U{} + V{})>

template <typename T>
class Vec3 {
public:
    static_assert(std::is_arithmetic_v<T>, "Type must be arithmetic");

    Vec3(T x, T y, T z) : _x(x), _y(y), _z(z) {}
    ~Vec3() = default;

    // matches any two Vec3<>s
    template <class U, class V>
    friend Vec3<decltype(U{} + V{})> operator+(const Vec3<U>& lhs,
                                               const Vec3<V>& rhs);

private:
    T _x, _y, _z;
};

template <class U, class V>
Vec3<decltype(U{} + V{})> operator+(const Vec3<U>& lhs, const Vec3<V>& rhs) {
    return {lhs._x + rhs._x, lhs._y + rhs._y, lhs._z + rhs._z};
}
b4lqfgs4

b4lqfgs42#

这并不是对所提问题的直接回答,而是演示了如果将数据组织成与范围兼容的形式,编写起来有多容易:

#include <array>
#include <functional>
#include <iostream>
#include <ranges>
#include <utility>

template <typename F, typename... R>
auto vsum(F&& f, R&& ...ranges)
{
    return std::views::zip_transform(
        std::forward<F>(f), std::forward<R>(ranges)...
    );
}

int main()
{
    std::array<int, 3> u{ 1, 2, 3 };
    std::array<double, 3> v{ 6.1, 6.2, 6.3 };

    for (auto e: vsum(std::plus{}, u, v))
        std::cout << e << '\n';
}

Compiler Explorer link.
如果需要,可以添加类型约束,但是vsum(std::plus{}, ...)会自动为任何具有合适operator+的对象工作。
我把它改成变元的,因为为了快速演示,它实际上可以减少输入,但是将它固定为两个范围参数是没有问题的,显然它也可以毫不费力地推广到任意维数。

相关问题