模板专业化与派生不匹配 class

Template specialization not matching derived class

我有一个 Textf class 可以存储格式化文本及其属性(目前只有颜色)。然后我有一个 Header class 从它派生并添加虚线下划线,有一些额外的属性等。

此外,我有一个单独的 println class(使用 class 用于部分专业化支持)。在其他类型中,我添加了对 Textf object 的支持。自然地,我假设(与函数一样)编译器会将 Header object 与 Textf 模板匹配。相反,我得到了 MSVC 错误 C2679(使用 VS 2019),这是因为编译器默认使用原始模板定义(因为 Textf 模式不匹配,因为 object 是 Header object).

如果我要为每个 child class 定义另一个模板特化,两个特化将具有完全相同的行为,使代码极其冗余(特别是如果有很多 child objects).

为清楚起见,这里有一些示例代码:

template<class LnTy>
class println  // Default template def
{
public:
    println(LnTy line)
    {
        std::cout << line;
    }
};

class Textf
{
protected:
    std::string_view m_text;
    Color m_text_color;  // Color is a scoped enum
    Color m_background_color;

public:
    // Constructors, etc...

    virtual void display() const
    {
        // Change color
        // Diplay text
        // Restore color
    }
};

class Header : public Textf
{
private:
    // 'U_COORD' is struct { unsigned X, Y; }
    U_COORD m_text_start_location;

public:
   // Constructors, etc...

    void display() const override
    {
        // Change color
        // Change cursor location
        // Display text
        // Display dashed underline (next line)
        // Restore cursor location (next line)
        // Restore color
    }
};

template<>
class println<Textf>  // Specialization for 'Textf'
{
    println(Textf line)
    {
        line.display();
    }
};

在这种情况下,如何利用模板中的多态性?

我遇到了其他问题并做了一些研究,但似乎我只能找到关于 child class 继承自模板 parent class,这不是我的困惑点。

如果有帮助,我正在使用 Windows 控制台 API 来更改文本的颜色。

您可以尝试从匹配默认模板中排除派生的 类:

template<class LnTy>
typename std::enable_if< !std::is_base_of<Textf, LnTy>::value >::type
class println  // Default template def
{
public:
    println(LnTy line)
    {
        std::cout << line;
    }
}

并使 "specialised" 版本成为非模板重载。

您可以使用 SFINAE 来确保使用正确的模板版本。

template<class LnTy, class = void> // second parameter is used in the specialization for SFINAE
class println  // Default template def
{
public:
    println(const LnTy& line)
    {
        std::cout << line;
    }
};

template<class LnTy>
class println<LnTy, std::enable_if_t<std::is_base_of_v<Textf, LnTy>>>
{
    println(const Textf& line)
    {
        line.display();
    }
};

如果使用 class 的唯一原因只是这个函数,您可以使用模板函数做同样的事情。

template<class LnTy, std::enable_if_t<!std::is_base_of_v<Textf, LnTy>, int> = 0>
void println(const LnTy& line)
{
    std::cout << line;
}

template<class LnTy, std::enable_if_t<std::is_base_of_v<Textf, LnTy>, int> = 0>
void println(const Textf& line)
{
    line.display();
}