首页 > 解决方案 > 如何在模板与联合之间进行继承?

问题描述

我有以下两个对象。我想知道是否有一种方法可以Pixel作为基类,PixelBGR以便可以使用任何运算符(+、-、*、/、[] 等)而无需重新定义它们?

template<class T, std::size_t N>
struct Pixel
{
    T ch[N];

    inline T& operator[](const int x)
    {
        return ch[x];
    }
};


template<class T>
struct PixelBGR
{
    union
    {
        struct
        {
            T b;
            T g;
            T r;
        };
        T ch[3];
    };

    inline T& operator[](const int x)
    {
        return ch[x];
    }
};

编辑:正如 πάντα ῥεῖ 所建议的,这里有更多关于我想要做什么的细节。

我试图拥有一个通用类Pixel,它将成为处理任何类型或大小的模板。

通常是 1、2、3、4、8 或 16。类定义了一些operator,如 +、-、* 等。

由于大多数时候Pixel<T,3>是 BGR 像素,我想定义快速访问r,以避免混淆gb但仍将其存储为 BGR。

但是派生类还应该提供基于N.

EDIT2:通过阅读 SergeyA 的评论,我忘了说结构Pixel不能改变大小。

所以我认为 balki 答案是最好的,通过使用成员函数。我试图用变量来避免过多的字符,即:添加 (),但它似乎太复杂了。我仍在研究 CRTP,但我不明白,我正在阅读。

标签: c++templatesunion

解决方案


Curiously Recurring Template Pattern (CRTP) 在这种情况下会很好地工作。在 CRTP 中,派生类用作基类的模板参数。David Vandevoorde 和 Nicolai M. Josuttis 所著的 C++ 模板 - 完整指南中的第 16.3 章奇怪重复的模板模式 (CRTP) 更详细地解释了一些事情。

从下面的评论中,使用 aunion{struct{...}...}会导致未定义的行为(UB),但对此存在一些矛盾的意见。据我所知,它是一个 gnu 扩展,几乎每个编译器都支持。glm例如union-structs经常使用。

作为替代方法,您可以为r,g,b变量使用别名(引用)。

#include <iostream>

template<typename T, std::size_t N, template<typename,std::size_t> class B >
struct Pixel
{
    B<T,N> *crtp = static_cast<B<T,N>*>(this);

    T& operator[](std::size_t x)
    {
        return crtp->ch[x];
    }

    Pixel& operator = (const Pixel &t)
    {
        crtp->ch[0] = t.crtp->ch[0];
        crtp->ch[1] = t.crtp->ch[1];
        crtp->ch[2] = t.crtp->ch[2];
        return *crtp;
    }

    B<T,N> operator + (const B<T,N> &t)
    {
        B<T,N> tmp;
        tmp[0] = crtp->ch[0] + t.crtp->ch[0];
        tmp[1] = crtp->ch[1] + t.crtp->ch[1];
        tmp[2] = crtp->ch[2] + t.crtp->ch[2];
        return tmp;
    }

    B<T,N> operator - (const B<T,N> &t)
    {
        B<T,N> tmp;
        tmp[0] = crtp->ch[0] - t.crtp->ch[0];
        tmp[1] = crtp->ch[1] - t.crtp->ch[1];
        tmp[2] = crtp->ch[2] - t.crtp->ch[2];
        return tmp;
    }
};

template<typename T, std::size_t N=3>
struct PixelBGR : Pixel<T, N, PixelBGR>
{
    T ch[3];
    T &r;
    T &g;
    T &b;

    PixelBGR() : ch{},r(ch[0]),g(ch[1]),b(ch[2])
    {}
    PixelBGR& operator = (const PixelBGR &p)
    {
        ch[0] = p.ch[0];
        ch[1] = p.ch[1];
        ch[2] = p.ch[2];
        return *this;
    }
};

int main()
{
    PixelBGR<int> p;

    p.r = 25;
    p.g = 14;
    p.b = 58;

    std::cout<< p[0] <<" , "<<p[1]<<" , "<<p[2] <<std::endl;

    PixelBGR<int> q;
    q = p;
    std::cout<< q[0] <<" , "<<q[1]<<" , "<<q[2] <<std::endl;

    PixelBGR<int> res1;
    res1 = q + p;
    std::cout<< res1.r <<" , "<<res1.g<<" , "<<res1.b <<std::endl;

    PixelBGR<int> res2;
    res2 = q - p;
    std::cout<< res2.r <<" , "<<res2.g<<" , "<<res2.b <<std::endl;
}

结果:

25 , 14 , 58
25 , 14 , 58
50 , 28 , 116
0 , 0 , 0

使用参考的示例:https ://rextester.com/AZWG4319

使用联合结构的示例:https ://rextester.com/EACC87146


推荐阅读