模板专业化不考虑继承层次结构。例如,如果我专门为Base
创建模板并使用Derived
对其进行实例化,则不会选择专门化(请参阅下面的代码(1))。
这可能是一个主要障碍,因为它有时会导致违反Liskov替代原则。例如,在处理this question时,我注意到我无法使用std::sub_match
使用Boost.Range算法,而std::pair
则可以使用sub_match
。由于pair
从sub_match
公开继承,常识会指示我可以在pair
处使用enable_if
替换is_base_of
,但由于使用模板专精化的特征类,这会失败。
我们可以通过使用部分模板专业化以及(1)
#include <iostream>
struct Base {};
struct Derived : public Base {};
template < typename T >
struct Foo
{
static void f() { std::cout << "Default" << std::endl; }
};
template <>
struct Foo< Base >
{
static void f() { std::cout << "Base" << std::endl; }
};
int main()
{
Foo<Derived>::f(); // prints "Default"
}
和(2)
#include <type_traits>
#include <iostream>
struct Base {};
struct Derived : public Base {};
template <typename T, typename Enable = void>
struct Foo
{
static void f() { std::cout << "Default" << std::endl; }
};
template <typename T>
struct Foo<
T, typename
std::enable_if< std::is_base_of< Base, T >::value >::type
>
{
static void f() { std::cout << "Base" << std::endl; }
};
int main()
{
Foo<Derived>::f(); // prints "Base"
}
来解决此问题(请参阅代码(2))。我是否总是喜欢这种解决方案而不是完全专业化,特别是在编写库代码时?我监督这种方法有什么缺点吗?这是您经常使用或经常使用的做法吗?
示例代码
{{1}}
{{1}}
答案 0 :(得分:13)
enable_if
更灵活我认为您应该更喜欢enable_if方法:它可以支持您需要的所有内容以及更多内容。
E.g。可能存在这样的情况:Derived类是Liskov-Subsitutable for Base,但是你[不能假设/不想要应用]相同的特征/特化是有效的(例如因为Base是POD类,而派生和非POD行为或类似于与类成分完全正交的行为)。
enable_if
使您能够准确定义条件。
您还可以通过实现一个traits类来实现一些中间函数,该类从通用特征派生一些特定于应用程序的特征。 “自定义”特征可以使用enable_if和元编程技术,根据需要以多态方式应用特征。这样,您的实际实现不必重复一些复杂的enable_if / dispatch舞蹈,而是可以简单地使用custom-traits类(隐藏复杂性)。
我认为一些(很多?)Boost库使用混合方法(我已经看到它以某种形式连接它,例如fusion / mpl,我认为Spirit中的各种迭代器特性)。
我个人喜欢这种方法,因为它可以有效地将“管道”与库的核心业务隔离开来,使维护和文档(!)变得更加容易。