繁体   English   中英

如何使用CRTP使用基类制作可选模板参数?

[英]How to make an optional template parameter with a base class using CRTP?

如何在下面的代码中使用CRTP使用基类创建可选模板参数?

template <unsigned int BYTES, OPTIONAL typename DerivedPrinter = MonoPrinter>  //DerivedPrinter should be optional. If it is not specified then it should default to MonoPrinter.
class MonoPrinter
{
protected:
    unsigned char CtrlCodes[BYTES] = { 0xFF };   //A code to initialize the printer

public:
    MonoPrinter()
    {
    }

    DerivedPrinter& print(const char* d)
    {
        for (int i=0; i<sizeof(CtrlCodes); i++)
          SendCtrlCode(CtrlCodes[i]);     //Initialize the printer and send additional control codes for color, font, etc...

        printf("Print Me: %s\n", d);  //This would actually send the string of chars to the printer (not to stdout) for printing
        return static_cast<DerivedPrinter&>(*this);     //Return a reference to the Derived Printer a la CRTP
    }
};

template <unsigned int BYTES>
class ColorPrinter : public MonoPrinter<BYTES, ColorPrinter>
{
public:
    ColorPrinter() : MonoPrinter()
    {
        static_assert(sizeof(CtrlCodes) >= 4);
        CtrlCodes[1] = 0xAA;
        CtrlCodes[2] = 0xBB;
        CtrlCodes[3] = 0xC0;
    }

    ColorPrinter& SetColor(unsigned char c)
    {
        CtrlCodes[3] = c;
        return *this;
    }
};


void main(void)
{
    MonoPrinter<1> iMonoPrinter;
    ColorPrinter<4> iColorPrinter;

    iMonoPrinter.print("Hello World").print(" we have no color");
    iColorPrinter.print("Hello World").SetColor(BLUE).print(" in Living Color");
}

PS
为了简单起见,上面的代码是人为的和删节的。
“ BYTES”模板参数不是可选的,必须始终指定。
我有与此代码的其他问题,但主要的问题是如何使“ DerivedPrinter”模板参数成为可选参数,因此不必总是指定它……并且当不是时,它应该默认为基类本身。

我想您可以(请参见下面的代码),但是我认为在这种情况下没有必要(请参见第二个示例)。

第一个示例,带有可选的template参数(请注意,这里PrinterTpl模板直接继承自具体的BasePrinter ,因此这里所有派生类MonoPrinterColorPrinter都继承自BasePrinter ):

template <unsigned int BYTES>
class BasePrinter
{
protected:
    unsigned char CtrlCodes[BYTES] = { 0xFF };

public:
    BasePrinter()
    {
        SendCtrlCode(CtrlCodes[0]);  //Initialize the printer
    }
};

template <unsigned int BYTES, typename DerivedPrinter = BasePrinter<BYTES>>  //DerivedPrinter should be optional. If it is not specified then it should default to PrinterTpl.
class PrinterTpl : public BasePrinter<BYTES>
{
public:
    PrinterTpl() : BasePrinter<BYTES>()
    {
    }

    DerivedPrinter& print(const char* d)
    {
        printf("Data: %s\n", d);
        return static_cast<DerivedPrinter&>(*this);     //Return a reference to the Derived Printer a la CRTP
    }
};

template <unsigned int BYTES>
class MonoPrinter : public PrinterTpl<BYTES, MonoPrinter<BYTES>>
{
public:
    MonoPrinter() : PrinterTpl<BYTES, MonoPrinter<BYTES>>()
    {
    }
};

template <unsigned int BYTES>
class ColorPrinter : public PrinterTpl<BYTES, ColorPrinter<BYTES>>
{
public:
    ColorPrinter() : PrinterTpl<BYTES, ColorPrinter<BYTES>>()
    {
        static_assert(sizeof(this->CtrlCodes) >= 4, "CtrlCodes too small");
        this->CtrlCodes[1] = 0xC1;
        this->CtrlCodes[2] = 0xC2;
        this->CtrlCodes[3] = 0xC3;
    }

    ColorPrinter& SetColor(int c)
    {
        assert(c < sizeof(this->CtrlCodes));
        SendCtrlCode(this->CtrlCodes[c+1]);
        return *this;
    }
};

第二个示例,没有模板可选参数(这里的PrinterTpl模板不需要从基础继承):

template <unsigned int BYTES, typename ConcretePrinter>
class PrinterTpl
{
protected:
    unsigned char CtrlCodes[BYTES] = { 0xFF };

public:
    PrinterTpl()
    {
        SendCtrlCode(this->CtrlCodes[0]);  //Initialize the printer
    }

    ConcretePrinter& print(const char* d)
    {
        printf("Data: %s\n", d);
        return static_cast<ConcretePrinter&>(*this);     //Return a reference to the Derived Printer a la CRTP
    }
};

template <unsigned int BYTES>
class MonoPrinter : public PrinterTpl<BYTES, MonoPrinter<BYTES>>
{
public:
    MonoPrinter() : PrinterTpl<BYTES, MonoPrinter<BYTES>>()
    {
    }
};

template <unsigned int BYTES>
class ColorPrinter : public PrinterTpl<BYTES, ColorPrinter<BYTES>>
{
public:
    ColorPrinter() : PrinterTpl<BYTES, ColorPrinter<BYTES>>()
    {
        static_assert(sizeof(this->CtrlCodes) >= 4, "CtrlCodes too small");
        this->CtrlCodes[1] = 0xC1;
        this->CtrlCodes[2] = 0xC2;
        this->CtrlCodes[3] = 0xC3;
    }

    ColorPrinter& SetColor(int c)
    {
        assert(c < sizeof(this->CtrlCodes));
        SendCtrlCode(this->CtrlCodes[c+1]);
        return *this;
    }
};

如果我没记错的话,这应该可以实现您的目标,并且我认为它更干净。

能够编写MonoPrinter<1>而不是MonoPrinter<1,dummy>并使第二个模板参数可选的关键是基类模板中的以下条件typedef typename类型名:

typedef typename std::conditional< std::is_same<Derived, void >::value, MonoPrinter, Derived >::type DerivedPrinter;  //Default to the MonoPrinter class if Derived == void

现在,下面的代码可以正确编译,并且不需要创建3rd类模板。 参见: https : //godbolt.org/g/awuck7

#include <type_traits>
#include <stdio.h>

#define BLUE 3

template <unsigned int BYTES, typename Derived = void>
class MonoPrinter
{
    typedef typename std::conditional< std::is_same<Derived, void >::value, MonoPrinter, Derived >::type DerivedPrinter;   //Default to the MonoPrinter class if Derived == void

protected:
    unsigned char CtrlCodes[BYTES];
    const unsigned char FinCode = 0xFF;

public:
    void SendCtrlCode(unsigned char c)
    {
        printf("<%02X>", c);    //This would actually send the string of control chars to the printer (not to stdout)
    }

    void InitializePrinter(void)
    {
        printf("\n");
        SendCtrlCode(CtrlCodes[0]);
        SendCtrlCode(0x00);
        SendCtrlCode(FinCode);
    }

    MonoPrinter()
    {
        CtrlCodes[0] = 0xEE;  //Set the default printer escape code
        InitializePrinter();
    }

    MonoPrinter(unsigned char c)
    {
        CtrlCodes[0] = c;  //A custom printer escape code
        InitializePrinter();
    }

    DerivedPrinter& print(const char* d)
    {
        for (int i = 0; i < sizeof(CtrlCodes); i++)
            SendCtrlCode(CtrlCodes[i]);     //Initialize the printer and send additional control codes for color, font, etc...
        SendCtrlCode(FinCode);

        printf("%s", d);  //This would actually send the string of chars to the printer (not to stdout) for printing
        return static_cast<DerivedPrinter&>(*this);     //Return a reference to the Derived Printer a la CRTP
    }

    int FooFn()
    {
        return 333;
    }
};


template <unsigned int BYTES>
class ColorPrinter : public MonoPrinter<BYTES, ColorPrinter<BYTES>>
{
protected:
    using MonoPrinter<BYTES, ColorPrinter<BYTES>>::CtrlCodes;
    //using MonoPrinter<BYTES, ColorPrinter<BYTES>>::FinCode;

public:
    //using MonoPrinter<BYTES, ColorPrinter<BYTES>>::MonoPrinter;
    using MonoPrinter<BYTES, ColorPrinter<BYTES>>::FooFn;
    //using MonoPrinter<BYTES, ColorPrinter<BYTES>>::InitializePrinter;
    //using MonoPrinter<BYTES, ColorPrinter<BYTES>>::SendCtrlCode;

    ColorPrinter()
    {
        static_assert(sizeof(this->CtrlCodes) >= 4, "CtrlCodes too small");
        CtrlCodes[1] = 0xDD;
        CtrlCodes[2] = 0xEE;
        CtrlCodes[3] = 0xC0;  //Default Color value
    }

    ColorPrinter(unsigned char c) : MonoPrinter<BYTES, ColorPrinter<BYTES>>::MonoPrinter(c)
    {
        static_assert(sizeof(this->CtrlCodes) >= 4, "CtrlCodes too small");
        CtrlCodes[1] = 0xDD;
        CtrlCodes[2] = 0xEE;
        CtrlCodes[3] = 0xC0;  //Default Color value
    }

    ColorPrinter& SetColor(unsigned char c)
    {
        CtrlCodes[3] = c;
        return *this;
    }

    int BooFn()
    {
        return FooFn() + 1;
    }
};


int main(void)
{
    MonoPrinter<1> iMonoPrinter;
    ColorPrinter<4> iColorPrinter(0xCC);

    iMonoPrinter.print("Hello World").print(" we have no color \n");
    iColorPrinter.print("Hello World").SetColor(BLUE).print(" in Living Color \n");

    printf(" %d\n", iColorPrinter.FooFn());
    printf(" %d\n", iColorPrinter.BooFn());

    return 0;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM