模板专业化与派生不匹配 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();
}
我有一个 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();
}