如何避免模棱两可的模板实例化?

问题描述

我正在尝试定义一个类,其行为以两种方式变化,当前基于两个不同的模板参数。 最初,我认为模板专业化只是通过功能增强了基类,因此我的想法是分别对两个参数进行部分专业化,希望这将使所有组合可用。 以下是我尝试执行的操作的示例:

// 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可能会有所帮助。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...