c++ - 如何避免不明确的模板实例化?

标签 c++ templates template-specialization

我试图定义一个类,其行为有两种变化,目前基于两个不同的模板参数。 最初我认为模板特化只是简单地增加了主类的功能,所以我的想法是分别部分特化这两个参数,希望这将使所有组合可用。 下面是我尝试做的一个例子:

// 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;

没有唯一的最特化,并且(来自 cppreference )

If more than one specialization matches, partial order rules are used to determine which specialization is more specialized. The most specialized specialization is used, if it is unique (if it is not unique, the program cannot be compiled) The compiler says that

显然这不是一个可行的方法,但更好的解决方案是什么? 我怀疑我以某种方式违反了单一职责原则,但我不太确定。 欢迎提出任何建议。

编辑:

Why do you need explicit instantation / specialization in 1st place?

最终,不同的专业也将管理不同的资源集;我不确定这是否相关,或者是一个充分的理由。 (我认识到我尝试做的事情会打开通向不同特化的大门,两者都声明一个同名变量,我想这是这不起作用的另一个原因。) 最主要的是实现高度/体重的所有组合,但我不确定该怎么做。

编辑: 删除了我添加的解决方案,因为来自@rustyx 的解决方案更好。 正如他们的回答中所指出的,它不允许交叉依赖,但在我的情况下,我认为依赖只是单向的(Weight 可能关心 Height,但是 Height 不关心 Weight),所以这不是问题。

最佳答案

您可以使用继承来增加“层”中功能的自由度。

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

关于c++ - 如何避免不明确的模板实例化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63836766/

相关文章:

c++ - 如何获取打开的 MDI child 的数量(计数)

c++ - 具有三元运算符和模板的自动

c++ - 如何解释函数模板解析?

c++ - 为什么常量的模板特化需要 const 变量

c++ - 避免使用虚方法构造具有空基类的构造函数

c++ - MongoDB 示例无法使用不同的标志进行编译

c++ - 图片库写错了

templates - 用模板初始化结构

c++ - 如何让编译器为派生类选择方法的非模板版本?

c++ - 依赖于构造函数参数的模板类特化?