[英]Good practices regarding template specialization and inheritance
Template specialization does not take into account inheritance hierarchy. 模板特化不考虑继承层次结构。 For example, if I specialize a template for
Base
and instantiate it with Derived
, the specialization will not be chosen (see code (1) below). 例如,如果我专门为
Base
创建模板并使用Derived
实例化它,则不会选择特化(参见下面的代码(1))。
This can be a major hindrance, because it sometimes lead to violation of the Liskov substitution principle. 这可能是一个主要障碍,因为它有时会导致违反Liskov替代原则。 For instance, while working on this question , I noticed that I could not use Boost.Range algorithms with
std::sub_match
while I could with std::pair
. 例如,在处理这个问题时 ,我注意到我无法使用
std::sub_match
Boost.Range算法,而我可以使用std::pair
。 Since sub_match
inherits publicly from pair
, common sense would dictate that I could substitute a sub_match
everywhere a pair
is used, but this fails due to trait classes using template specialization. 由于
sub_match
从pair
公开继承,常识将指示我可以在使用pair
任何地方替换sub_match
,但是由于使用模板特化的trait类而失败。
We can overcome this issue by using partial template specialization along with enable_if
and is_base_of
(see code (2)). 我们可以通过使用部分模板特化以及
enable_if
和is_base_of
来解决此问题(请参阅代码(2))。 Should I always favor this solution over full specialization, especially when writing library code? 我是否总是喜欢这种解决方案而不是完全专业化,特别是在编写库代码时? Are there any drawbacks to this approach that I have overseen?
我监督这种方法有什么缺点吗? Is it a practice that you use or have seen used often?
这是您经常使用或经常使用的做法吗?
Sample codes 示例代码
(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"
}
enable_if
is more flexible enable_if
更灵活 I think you should really prefer the enable_if approach: it enables everything that you could require and more. 我认为您应该更喜欢enable_if方法:它可以支持您需要的所有内容以及更多功能。
Eg there might be cases where a Derived class is Liskov-Subsitutable for a Base, but you [cannot assume/donot want to apply] the same traits/specializations to be valid (eg because the Base is POD class, whereas Derived ands non-POD behaviour or somehting like that that is completely orthogonal to class composition). 例如,可能存在Derived类是Liskov-Subsitutable for Base的情况, 但您[不能假设/不想要应用]相同的特征/特化是有效的(例如因为Base是POD类,而Derived和非非) POD行为或类似于与类成分完全正交的行为。
enable_if
gives you the power to define exactly the conditions. enable_if
使您能够准确定义条件。
You could also achieve some middleground by implementing a traits class that derives some application-specific traits from general-purpose traits. 您还可以通过实现一个traits类来实现一些中间件,该类从通用特征派生一些特定于应用程序的特征。 The 'custom' traits could use the enable_if and meta-programming techniques to apply traits as polymorphically as you desire.
“自定义”特征可以使用enable_if和元编程技术,根据需要以多态方式应用特征。 That way, your actual implementations do not have to repeat some complicated enable_if/dispatch dance but instead can simply consume the custom-traits class (that hides the complexity).
这样,您的实际实现不必重复一些复杂的enable_if / dispatch舞蹈,而是可以简单地使用custom-traits类(隐藏复杂性)。
I think some (many?) Boost libraries use the hybrid approach (I've seen it in some capacity where it bridges eg fusion/mpl, I think also various iterator traits in Spirit). 我认为一些(很多?)Boost库使用混合方法(我已经看到它以某种形式连接它,例如fusion / mpl,我认为Spirit中的各种迭代器特性)。
I personally like this approach because it can effectively isolate the 'plumbing' from the core-business of a library, making maintenance and documentation (!) a lot easier. 我个人喜欢这种方法,因为它可以有效地将“管道”与库的核心业务隔离开来,使维护和文档 (!)变得更加容易。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.