[英]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
,因此这里所有派生类MonoPrinter
和ColorPrinter
都继承自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.