繁体   English   中英

模板特化与派生类不匹配

[英]Template specialization not matching derived class

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

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

如果我要为每个子类定义另一个模板特化,两个特化将具有完全相同的行为,从而使代码变得极其冗余(尤其是在有许多子对象的情况下)。

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

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();
    }
};

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

我遇到了其他问题并做了一些研究,但似乎我只能找到关于从模板父类继承的子类的事情,这不是我在这里的困惑点。

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

您可以使用 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();
    }
};

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

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();
}

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

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

并使“专业”版本成为非模板重载。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM