Синтаксис для специализации вложенного шаблона

Я пытаюсь выяснить правильный синтаксис для явной специализации вложенного шаблона. Следующий код лучше иллюстрирует:

struct Column_Major;
struct Row_Major;

template<size_t rows, size_t cols, typename T, typename Allocator>
class Matrix
{

    /* bunch of members */
    template <typename storage = Column_Major>
    class Iterator
    {
        /* bunch of members */
    };
};

Я хотел бы написать явную специализацию для template <> class Matrix<...>::Iterator<Row_Major, но синтаксис ускользает от меня. У меня есть подозрение, что нельзя явно специализировать класс Iterator без явной специализации содержащего класса Matrix. Но я был бы очень рад, если есть способ сделать это.

Я знаю, что я мог бы сделать класс Iterator отдельным классом, а не членом класса Matrix, но наличие вложенных в него классов позволяет мне получить полный доступ к параметрам шаблона и datamebers класса Matrix, что упрощает работу. Я знаю, что могу обойти это, если нужно, но сначала хотел бы изучить и понять возможности для вложенного подхода.

Спасибо, Шмуэль

Ответ 1

Для явной специализации вам нужно специализировать внешний класс перед внутренним, вы можете увидеть этот вопрос, например.

Существует обходное решение, использующее частичную специализацию:

template<size_t rows, size_t cols, typename T, typename Allocator>
class Matrix
{

    //                           Notice the additionnal dummy parameter
    //                                       vvvvvvvvvvvvv
    template <typename storage = Column_Major, bool = true>
    class Iterator
    {
    };

    // Specialization
    template <bool dummy>
    class Iterator<Row_Major, dummy>
    {
    };
};

Ответ 2

Вы можете сделать ответ Synxis (использование параметра фиктивного дефиниции) еще более чистым с С++ 11:

/// template <typename X>, not needed for the example
struct Outer
{
private:
    template <typename A, typename D = void>
    struct Inner
    {
        Inner()  { cout << "default" << endl; }
    };
    template <typename D>
    struct Inner<int,D>
    {
        Inner()  { cout << "int" << endl; }
    };  
public:
    template <typename T>
    using  Nested = Inner<T>;
};

Преимущество этого улучшения заключается в том, что подпись Nested имеет только один параметр шаблона, который, я думаю, поможет, если вы хотите правильно его сопоставить в метапрограмме шаблона.

Ответ 3

Я удивлен, что параметр шаблона для вложенного класса не является параметром родительского класса.

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

Я бы сделал это вот так:

template <class T>
class Outer
{
public:
    class Inner
    {
        void Fn( T in )
        {
        }
    };
};

// specialisation
void Outer<double>::Inner::Fn( double in )
{

}