如何使用以下代码中的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");
}
P.S。
上面的代码是为了简单而设计和删节。
&#34; BYTES&#34; template参数不是可选的,必须始终指定
我有这个代码的其他问题,但主要的是如何使&#34; DerivedPrinter&#34;模板参数是可选的,因此并不总是必须指定...而当它不是 - 它应该默认为基类本身。
答案 0 :(得分:2)
我想你可以(见下面的代码),但我认为在这种情况下没有必要(见第二个例子)。
第一个示例,使用可选的模板参数(请注意,此处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;
}
};
如果我没有弄错的话,这应该达到你的目标,而且我认为它更清洁。
答案 1 :(得分:1)
能够编写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
下面的代码现在编译时没有错误,也不需要创建第3类模板。请参阅: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;
}