Хорошие практики в отношении специализации и наследования шаблонов

Специализация шаблона не принимает во внимание иерархию наследования. Например, если я специализирую шаблон для База и его экземпляр с помощью Производный , специализация не будет выбрана (см. Код (1) ниже).

Это может быть серьезным препятствием, поскольку иногда приводит к нарушению принцип подстановки Лискова. Например, работая над этим вопросом , я заметил, что не могу использовать алгоритмы Boost.Range с std :: sub_match , тогда как я мог бы с std :: pair . Поскольку sub_match публично наследуется от пары , здравый смысл подсказывает, что я мог бы везде заменить sub_match парой ], но это не удается из-за классов признаков, использующих специализацию шаблонов.

Мы можем преодолеть эту возникает при использовании частичной специализации шаблона вместе с enable_if и is_base_of (см. код (2)).Должен ли я всегда отдавать предпочтение этому решению, а не полной специализации, особенно при написании кода библиотеки? Есть ли у этого подхода недостатки, которые я заметил? Вы используете эту практику или часто видели?


Примеры кодов

(1)
#include 

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::f(); // prints "Default"
}

(2)
#include 
#include 

struct Base {};
struct Derived : public Base {};

template 
struct Foo
{
    static void f() { std::cout << "Default" << std::endl; }
};

template 
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::f(); // prints "Base"
}

23
задан Community 23 May 2017 в 12:33
поделиться