问题描述
我正在尝试定义一个类,其行为以两种方式变化,当前基于两个不同的模板参数。 最初,我认为模板专业化只是通过功能增强了基类,因此我的想法是分别对两个参数进行部分专业化,希望这将使所有组合可用。 以下是我尝试执行的操作的示例:
// specify the ways in which people can vary
enum class Weight { Skinny,Fat };
enum class Height { Short,Tall };
// primary class
template<Weight W,Height H>
struct Person
{
const char* name = "name";
void SayHello(void);
void SayGoodbye(void);
};
// first specialize how a person says hello,based on their weight
template<Height H>
struct Person<Weight::Skinny,H>
{
const char* goal = "ride a bike";
void SayHello(void) {
printf("Hello,I am skinny %s.\n",name);
printf("My goal is to %s.\n",goal);
}
};
template<Height H>
struct Person<Weight::Fat,H>
{
const char* show = "movies";
void SayHello(void) {
printf("Hello,I am fat %s.\n",name);
printf("My favorite show is %s.\n",show);
}
};
// then specialize how a person says goodbye,based on their height
template<Weight W>
struct Person<W,Height::Short>
{
void SayGoodbye(void) { printf("Goodbye,I am short %s.\n",name); }
};
template<Weight W>
struct Person<W,Height::Tall>
{
void SayGoodbye(void) { printf("Goodbye,I am tall %s.\n",name); }
};
这不起作用,因为当我尝试实例化Person
时
Person<Weight::Skinny,Height::Short> X;
没有唯一的最专业的专业化课程,并且(来自Decrypt file encrypted using openssl with aes-cbc-256)
如果多个专业匹配,则使用偏序规则来确定哪个专业更专业。如果是唯一的,则使用最专业的专业(如果不是唯一的,则无法编译程序) 编译器说
显然,这不是可行的方法,但是什么是更好的解决方案? 我怀疑自己在某种程度上违反了单一责任原则,但我不太确定。 任何建议都将受到欢迎。
编辑:
为什么您需要在第一位置进行显式实例化/特化?
最终,不同的专业也将管理不同的资源集;我不确定这是否相关,还是很好的理由。 (我认识到我试图做的事情将为不同的专业打开大门,它们都声明了相同名称的变量,这是我不希望这样做的另一个原因。) 最主要的是要实现身高/体重的所有组合,但我不确定该怎么做。
编辑:
删除了我添加的解决方案,因为来自@rustyx的解决方案更好。
如他们的回答所述,它不允许交叉依赖,但就我而言,我认为依赖仅是单向的(Weight
可能关心Height
,而Height
并不关心Weight
),所以这不是问题。
解决方法
您可以简单地在函数中使用if
条件来确定要打印的消息,如下所示:
template<Weight W,Height H>
struct Person
{
void SayHello(void) {
if (W == Weight::Skinny)
std::cout << "Hello,I am skinny.\n";
else
std::cout << "Hello,I am fat.\n";
}
void SayGoodbye(void) {
if (H == Height::Short)
std::cout << "Goodbye,I am short.\n";
else
std::cout << "Goodbye,I am tall.\n";
}
};
这里是demo。
,您可以使用继承来增加“图层”中功能的自由度。
enum class Weight { Skinny,Fat };
enum class Height { Short,Tall };
struct PersonBase {
const char* name = "name";
};
template<Weight W>
struct PersonWeight : PersonBase {
void SayHello();
};
template<Weight W,Height H>
struct PersonHeight : PersonWeight<W> {
void SayGoodbye();
};
template<Weight W,Height H>
struct Person : PersonHeight<W,H> {
};
template<>
struct PersonWeight<Weight::Skinny> : PersonBase {
const char* goal = "ride a bike";
void SayHello() {
printf("Hello,I am skinny %s.\n",name);
printf("My goal is to %s.\n",goal);
}
};
template<>
struct PersonWeight<Weight::Fat> : PersonBase {
const char* show = "movies";
void SayHello() {
printf("Hello,I am fat %s.\n",name);
printf("My favorite show is %s.\n",show);
}
};
template<Weight W>
struct PersonHeight<W,Height::Short> : PersonWeight<W> {
void SayGoodbye() { printf("Goodbye,I am short %s.\n",name); }
};
template<Weight W>
struct PersonHeight<W,Height::Tall> : PersonWeight<W> {
void SayGoodbye() { printf("Goodbye,I am tall %s.\n",name); }
};
但是,如果各层之间存在交叉依赖性,则此方法将无效。在这种情况下,if constexpr
或SFINAE可能会有所帮助。