【问题标题】:Wrong Operator Overloading, CRTP, C++错误的运算符重载、CRTP、C++
【发布时间】:2020-12-04 19:15:38
【问题描述】:

我正在使用CRTP 进行运算符重载。我有 基础结构

template<int S, typename T, typename C>
struct ColorModel {
    constexpr static int SPACE = S;

    ColorModel() {
        std::fill(begin(), end(), 0);
    }

    ColorModel(const ColorModel& another) {
        std::copy(another.begin(), another.end(), begin());
    }

    ColorModel(ColorModel&& another) noexcept {
        std::move(another.begin(), another.end(), begin());
    }

    ColorModel(const std::initializer_list<T>& l) {
        std::copy(l.begin(), l.end(), begin());
    }

    explicit ColorModel(const T& elem) {
        std::fill(begin(), end(), elem);
    }

    constexpr inline const T* cbegin() const {
        return static_cast<const C*>(this)->components.cbegin();
    }

    constexpr inline const T* cend() const {
        return static_cast<const C*>(this)->components.cend();
    }

    constexpr inline const T* begin() const {
        return cbegin();
    }

    constexpr inline const T* end() const {
        return cend();
    }

    constexpr inline T* begin() {
        return static_cast<C*>(this)->components.begin();
    }

    constexpr inline T* end() {
        return static_cast<C*>(this)->components.end();
    }

    constexpr inline size_t size() const {
        return std::distance(begin(), end());
    }

    constexpr inline ColorModel& operator=(const ColorModel& rhs) {
        std::copy(rhs.begin(), rhs.end(), begin());
        return *this;
    }

    constexpr inline ColorModel& operator=(ColorModel&& rhs) noexcept {
        std::move(rhs.begin(), rhs.end(), begin());
        return *this;
    }

    constexpr inline ColorModel& operator=(const T& rhs) {
        std::fill(begin(), end(), rhs);
        return *this;
    }

    constexpr inline ColorModel& operator=(T&& rhs) {
        std::fill(begin(), end(), rhs);
        return *this;
    }

    constexpr inline ColorModel& operator+=(const ColorModel& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::plus<>());
        return *this;
    }

    constexpr inline ColorModel& operator+=(ColorModel&& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::plus<>());
        return *this;
    }

    constexpr inline ColorModel& operator+=(const T& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::plus<>());
        return *this;
    }

    constexpr inline ColorModel& operator+=(T&& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::plus<>());
        return *this;
    }

    constexpr inline ColorModel& operator-=(const ColorModel& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::minus<>());
        return *this;
    }

    constexpr inline ColorModel& operator-=(ColorModel&& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::minus<>());
        return *this;
    }

    constexpr inline ColorModel& operator-=(const T& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::minus<>());
        return *this;
    }

    constexpr inline ColorModel& operator-=(T&& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::minus<>());
        return *this;
    }

    constexpr inline ColorModel& operator*=(const ColorModel& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::multiplies<>());
        return *this;
    }

    constexpr inline ColorModel& operator*=(ColorModel&& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::multiplies<>());
        return *this;
    }

    constexpr inline ColorModel& operator*=(const T& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::multiplies<>());
        return *this;
    }

    constexpr inline ColorModel& operator*=(T&& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::multiplies<>());
        return *this;
    }

    constexpr inline ColorModel& operator/=(const ColorModel& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::divides<>());
        return *this;
    }

    constexpr inline ColorModel& operator/=(ColorModel&& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::divides<>());
        return *this;
    }

    constexpr inline ColorModel& operator/=(const T& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::divides<>());
        return *this;
    }

    constexpr inline ColorModel& operator/=(T&& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::divides<>());
        return *this;
    }

    constexpr inline ColorModel operator+(const ColorModel& rhs) const {
        ColorModel result;
        std::transform(begin(), end(), rhs.begin(), result.begin(), std::plus<>());
        return result;
    }

    constexpr inline ColorModel operator+(ColorModel&& rhs) const {
        ColorModel result;
        std::transform(begin(), end(), rhs.begin(), result.begin(), std::plus<>());
        return result;
    }

    constexpr inline ColorModel operator+(const T& rhs) const {
        ColorModel result;
        util::transform(begin(), end(), rhs, result.begin(), std::plus<>());
        return result;
    }

    constexpr inline ColorModel operator+(T&& rhs) const {
        ColorModel result;
        util::transform(begin(), end(), rhs, result.begin(), std::plus<>());
        return result;
    }

    constexpr inline ColorModel operator-(const ColorModel& rhs) const {
        ColorModel result;
        std::transform(begin(), end(), rhs.begin(), result.begin(), std::minus<>());
        return result;
    }

    constexpr inline ColorModel operator-(ColorModel&& rhs) const {
        ColorModel result;
        std::transform(begin(), end(), rhs.begin(), result.begin(), std::minus<>());
        return result;
    }

    constexpr inline ColorModel operator-(const T& rhs) const {
        ColorModel result;
        util::transform(begin(), end(), rhs, result.begin(), std::minus<>());
        return result;
    }

    constexpr inline ColorModel operator-(T&& rhs) const {
        ColorModel result;
        util::transform(begin(), end(), rhs, result.begin(), std::minus<>());
        return result;
    }

    constexpr inline ColorModel operator*(const ColorModel& rhs) const {
        ColorModel result;
        std::transform(begin(), end(), rhs.begin(), result.begin(), std::multiplies<>());
        return result;
    }

    constexpr inline ColorModel operator*(ColorModel&& rhs) const {
        ColorModel result;
        std::transform(begin(), end(), rhs.begin(), result.begin(), std::multiplies<>());
        return result;
    }

    constexpr inline ColorModel operator*(const T& rhs) const {
        ColorModel result;
        util::transform(begin(), end(), rhs, result.begin(), std::multiplies<>());
        return result;
    }

    constexpr inline ColorModel operator*(T&& rhs) const {
        ColorModel result;
        util::transform(begin(), end(), rhs, result.begin(), std::multiplies<>());
        return result;
    }

    constexpr inline ColorModel operator/(const ColorModel& rhs) const {
        ColorModel result;
        std::transform(begin(), end(), rhs.begin(), result.begin(), std::divides<>());
        return result;
    }

    constexpr inline ColorModel operator/(ColorModel&& rhs) const {
        ColorModel result;
        std::transform(begin(), end(), rhs.begin(), result.begin(), std::divides<>());
        return result;
    }

    constexpr inline ColorModel operator/(const T& rhs) const {
        ColorModel result;
        util::transform(begin(), end(), rhs, result.begin(), std::divides<>());
        return result;
    }

    constexpr inline ColorModel operator/(T&& rhs) const {
        ColorModel result;
        util::transform(begin(), end(), rhs, result.begin(), std::divides<>());
        return result;
    }
};

template<int S, typename T, typename C>
std::ostream& operator<<(std::ostream& os, const ColorModel<S, T, C>& model) {
    for (const auto& elem : model) {
        os << elem << " ";
    }
    return os;
}

这是基础结构的

struct RGB : ColorModel<0, int, RGB> {
    std::array<int, 3> components;

    RGB() : ColorModel() {

    }

    RGB(const RGB& other) : ColorModel(other) {

    }

    RGB(RGB&& other) : ColorModel(other) {

    }

    RGB(const std::initializer_list<int>& l) : ColorModel(l) {

    }

    explicit RGB(const int& elem) : ColorModel(elem) {

    }

    using ColorModel<0, int, RGB>::operator=;
};

这是我的util::transform函数的代码

namespace util {
    template<typename Iterator, typename T, typename BinaryOperator>
    void transform(Iterator begin, Iterator end, const T& elem, Iterator result, BinaryOperator anOperator) {
        for (; begin != end; ++begin, ++result) {
            *result = anOperator(*begin, elem);
        }
    }
}

但是当我开始在 main.cpp 中测试它时,我得到了奇怪的结果。

int main() {
    RGB rgb1{1, 2, 3};
    RGB rgb2{2, 3, 4};

    RGB rgb3(10);
    rgb3 += rgb3 + rgb1+rgb2;
    std::cout << rgb3 << std::endl << rgb1 << std::endl << rgb2;
}

我得到10 15 20 而不是13 15 17,我一直试图找出原因。 提前谢谢。

附:对不起所有 constexpr inline 我只是在本地测试一些东西。

【问题讨论】:

  • @NathanOliver 是的,我忘了更新复制粘贴的部分,谢谢)
  • 您应该真正测试您提供给我们的 MCVE,以确保问题仍然可以重现。
  • 什么是util?你有自己的功能吗?
  • 对不起,这是我的功能,与问题无关,我已经更新并删除了它。

标签: c++ operator-overloading parentheses crtp


【解决方案1】:

您的(主要)问题是您在基类 (ColorModel) 为其设置了一些值之后(非)初始化 component

您可能在组件的显式初始化中遇到一致的错误:

explicit RGB(const int& elem) : ColorModel(elem), component{} {}

Demo

你可以使用base from member idiom来解决它。

struct Data
{
    std::array<int, 3> components{};
};

struct RGB : Data, ColorModel<0, int, RGB> {
// ...
};

Demo

您的operator+ 也有问题,因为ColorModel result; 无效(那里没有派生类),它应该是C result;(与返回类型相同)。

【讨论】:

  • 我按照你说的更新了代码,改动很小,我会尽快发布答案,谢谢)
【解决方案2】:

正如@Jarod42 提到的,我需要根据需要更新基本颜色空间结构。我做了以下更新。

template<int S, typename T, typename C>
struct ColorModel {

    constexpr inline const T* cbegin() const {
        return static_cast<const C*>(this)->components.cbegin();
    }

    constexpr inline const T* cend() const {
        return static_cast<const C*>(this)->components.cend();
    }

    constexpr inline const T* begin() const {
        return cbegin();
    }

    constexpr inline const T* end() const {
        return cend();
    }

    constexpr inline T* begin() {
        return static_cast<C*>(this)->components.begin();
    }

    constexpr inline T* end() {
        return static_cast<C*>(this)->components.end();
    }

    constexpr inline ColorModel& operator=(const C& rhs) {
        std::copy(rhs.begin(), rhs.end(), begin());
        return *this;
    }

    constexpr inline ColorModel& operator=(C&& rhs) {
        std::move(rhs.begin(), rhs.end(), begin());
        return *this;
    }

    constexpr inline ColorModel& operator=(const T& rhs) {
        std::fill(begin(), end(), rhs);
        return *this;
    }

    constexpr inline ColorModel& operator=(T&& rhs) {
        std::fill(begin(), end(), rhs);
        return *this;
    }

    constexpr inline ColorModel& operator+=(const C& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::plus<>());
        return *this;
    }

    constexpr inline ColorModel& operator+=(C&& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::plus<>());
        return *this;
    }

    constexpr inline ColorModel& operator+=(const T& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::plus<>());
        return *this;
    }

    constexpr inline ColorModel& operator+=(T&& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::plus<>());
        return *this;
    }

    constexpr inline ColorModel& operator-=(const C& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::minus<>());
        return *this;
    }

    constexpr inline ColorModel& operator-=(C&& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::minus<>());
        return *this;
    }

    constexpr inline ColorModel& operator-=(const T& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::minus<>());
        return *this;
    }

    constexpr inline ColorModel& operator-=(T&& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::minus<>());
        return *this;
    }

    constexpr inline ColorModel& operator*=(const C& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::multiplies<>());
        return *this;
    }

    constexpr inline ColorModel& operator*=(C&& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::multiplies<>());
        return *this;
    }

    constexpr inline ColorModel& operator*=(const T& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::multiplies<>());
        return *this;
    }

    constexpr inline ColorModel& operator*=(T&& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::multiplies<>());
        return *this;
    }

    constexpr inline ColorModel& operator/=(const C& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::divides<>());
        return *this;
    }

    constexpr inline ColorModel& operator/=(C&& rhs) {
        std::transform(begin(), end(), rhs.begin(), begin(), std::divides<>());
        return *this;
    }

    constexpr inline ColorModel& operator/=(const T& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::divides<>());
        return *this;
    }

    constexpr inline ColorModel& operator/=(T&& rhs) {
        util::transform(begin(), end(), rhs, begin(), std::divides<>());
        return *this;
    }

    constexpr inline C operator+(const C& rhs) const {
        C res;
        std::transform(begin(), end(), rhs.begin(), res.begin(), std::plus<>());
        return res;
    }

    constexpr inline C operator+(C&& rhs) const {
        C res;
        std::transform(begin(), end(), rhs.begin(), res.begin(), std::plus<>());
        return res;
    }

    constexpr inline C operator+(const T& rhs) const {
        C res;
        util::transform(begin(), end(), rhs, res.begin(), std::plus<>());
        return res;
    }

    constexpr inline C operator+(T&& rhs) const {
        C res;
        util::transform(begin(), end(), rhs, res.begin(), std::plus<>());
        return res;
    }

    constexpr inline C operator-(const C& rhs) const {
        C res;
        std::transform(begin(), end(), rhs.begin(), res.begin(), std::minus<>());
        return res;
    }

    constexpr inline C operator-(C&& rhs) const {
        C res;
        std::transform(begin(), end(), rhs.begin(), res.begin(), std::minus<>());
        return res;
    }

    constexpr inline C operator-(const T& rhs) const {
        C res;
        util::transform(begin(), end(), rhs, res.begin(), std::minus<>());
        return res;
    }

    constexpr inline C operator-(T&& rhs) const {
        C res;
        util::transform(begin(), end(), rhs, res.begin(), std::minus<>());
        return res;
    }

    constexpr inline C operator*(const C& rhs) const {
        C res;
        std::transform(begin(), end(), rhs.begin(), res.begin(), std::multiplies<>());
        return res;
    }

    constexpr inline C operator*(C&& rhs) const {
        C res;
        std::transform(begin(), end(), rhs.begin(), res.begin(), std::multiplies<>());
        return res;
    }

    constexpr inline C operator*(const T& rhs) const {
        C res;
        util::transform(begin(), end(), rhs, res.begin(), std::multiplies<>());
        return res;
    }

    constexpr inline C operator*(T&& rhs) const {
        C res;
        util::transform(begin(), end(), rhs, res.begin(), std::multiplies<>());
        return res;
    }

    constexpr inline C operator/(const C& rhs) const {
        C res;
        std::transform(begin(), end(), rhs.begin(), res.begin(), std::divides<>());
        return res;
    }

    constexpr inline C operator/(C&& rhs) const {
        C res;
        std::transform(begin(), end(), rhs.begin(), res.begin(), std::divides<>());
        return res;
    }

    constexpr inline C operator/(const T& rhs) const {
        C res;
        util::transform(begin(), end(), rhs, res.begin(), std::divides<>());
        return res;
    }

    constexpr inline C operator/(T&& rhs) const {
        C res;
        util::transform(begin(), end(), rhs, res.begin(), std::divides<>());
        return res;
    }
};

template<int S, typename T, typename C>
std::ostream& operator<<(std::ostream& os, const ColorModel<S, T, C>& model) {
    std::for_each(model.begin(), model.end(), [&](const T& elem) { os << elem << " "; });
    return os;
}

如您所见,我基类中删除了所有构造函数,因为它主要用于运算符重载并让子结构初始化它以自己的方式拥有自己的领域。所以我的struct RGB更新如下

struct RGB : color_space::ColorModel<0, int, RGB> {
    std::array<int, 3> components{};

    RGB() = default;

    RGB(const std::initializer_list<int>& l){
        std::copy(l.begin(),l.end(),components.begin());
    }

    // All constructors you want

    using color_space::ColorModel<0, int, RGB>::operator=;
};

这解决了没有初始化我的std::array&lt;int,3&gt; components的问题 此外,我还必须更改创建 new instance of C(Child) 的所有运算符重载的实现。并相应地更改返回类型。 谢谢。

【讨论】:

    猜你喜欢
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-14
    • 2016-10-18
    • 1970-01-01
    相关资源
    最近更新 更多