Частичная специализация С++ в операторе наследования?

Так что я попал в затруднительное положение с шаблонами C++. Предполагая, что у меня есть иерархия контейнерных классов вида:

template <class T>
class AContainer{
    // ...
};

И через наследование делаются разные контейнеры с разными внутренними представлениями:

template <class T>
class AVectorLikeContainer: public AContainer<T>{
    // ...
};

И куча иерархий оператороподобных классов, которые имеют форму:

template <template <class T> class C, class T>
class AnOperator{
public:
    virtual T operator() (const C<T> &c1, const C<T> &c2);
    // ...
};

Используя операторы наследования и частичной специализации, такие как эти:

template <class T>
class AnOperatorForVectorLike: public AnOperator<AvectorLikeContainer, T>{
public:
     virtual T operator() (const AVectorLikeContainer<T> &c1, const AVectorLikeContainer<T> &c2);
     // ...
};

Теперь чуть позже в проекте контейнеры вида:

template <class T, std::size_t N>
class AStaticSizeContainer: public AContainer<T>{
    // ...
};

были введены. Очевидно, что это нарушает дизайн, поскольку AStaticSizeContainer не соответствует части template <class T> class C сигнатуры шаблона AnOperator. Чтобы обойти это, нужно ввести метафункцию, например:

template <class T, std::size_t N>
class StaticSizer{
public:
    template <class T1>
    class SizedStaticContainer: public AStaticSizeContainer<N, T1>{
        // ...
    };
};

Таким образом, StaticSizer<25>::SizedStaticContainer — это класс, соответствующий сигнатуре шаблона template <class T> class C. Однако у этого есть несколько недостатков. Первый и очевидный — это необходимость всегда использовать StaticSize<N>::SizedStaticContainer<T> вместо AStaticSizeContainer<T, N>, даже если T и N «известны». Это вызвано тем, что они не взаимозаменяемы (один наследуется от другого). Второй недостаток заключается в том, что все конструкторы AStaticSizeContainer должны быть буквально скопированы для StaticSizer::SizedStaticContainer. Я уверен, что есть и другие, на которые я еще не наткнулся.

Итак, мои вопросы следующие:

Есть ли более элегантный способ исправить это в соответствии с уже выложенным интерфейсом? В более широком смысле, можем ли мы указать частичную специализацию класса более элегантным способом? В более узком смысле, есть ли у нас синтаксис, чтобы сказать что-то вроде:

template <class T, std::size_t N>
class AnOperatorForStaticSize: public AnOperator<AStaticSizeContainer<with N = N>, T>{
    // ...
};

где под AStaticSizeContainer<with N = N> я подразумеваю частичную специализацию AStaticSizeContainer с N из приведенного выше шаблона.

ИЗМЕНИТЬ C++11 шаблоны псевдонимов, по-видимому будет работать, но мне нужна альтернатива С++ 03.




Ответы (1)


На заре C++ люди экспериментировали с множеством подобных подходов, и ни один из них не сработал. Вполне возможно, что на основе опыта последних почти 20 лет можно было бы разработать лучший подход, но кажется, что универсальное программирование (представленное в форме STL) предоставило рабочее решение, в котором нет ни одной из проблем, которые вы описываете. Основная идея решения заключается в фундаментальном подходе к решению проблем в информатике: ввести дополнительный уровень косвенности. Вместо того, чтобы привязывать структуру к операторам, вы должны реализовать операторы в терминах обобщенного метода доступа к структуре. В STL структуры — это последовательности, операторы — алгоритмы, а связующее звено между ними — итераторы.

person Dietmar Kühl    schedule 15.09.2013