13
votes

I'm trying to figure out the correct syntax for explicit specialization of a nested template class. The following code will better illustrate:

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 */
    };
};

I'd like to write an explicit specialization for template <> class Matrix<...>::Iterator<Row_Major, but the syntax is eluding me. I have a suspicion that it is not possible to explicitly specialize the Iterator class without an explicit specialization of the containing class, Matrix. But I would be very happy if there is a way to do this.

I know I could make the Iterator class a separate class, not a member of the Matrix class, but having the classes nested as such allows me full access to the template parameters and datamebers of the Matrix class, which simplifies things. I know I could work around this if I need to, but I'd first like to investigate and understand the possibilities for the nested approach.

Thanks, Shmuel

3
Shouldn't the matrix itself know its storage type?n. 1.8e9-where's-my-share m.
[temp.expl.spec]/16 "In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well." And /2 "An explicit specialization shall be declared in a namespace enclosing the specialized template"dyp
@n.m., In this design, the storage type for Matrix is always column-major. The ability to have a row-major iterator is intended, among other reasons, to allow the contents of a matrix to be read from a stream, where the source data is necessarily in a row-major format.Shmuel Levine

3 Answers

17
votes

For explicit specialization, you need to specialize the outer class before the inner, you can see this question for example.

There is a workaround that is using partial specialization:

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
votes

You can make Synxis answer (use of defaulted dummy parameter) even more clean with C++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>;
};

The advantage of this improvement is that the signature of Nested has only one template parameter, which I think will help if you want to match it correctly in template meta-programming.

0
votes

I'm surprised the template parameter for the nested class isn't a parameter of the parent class instead.

The nested class can use the template parameters of the parent and this more closely ties the nested class to the parent. Your use of the word iterator suggests this is good, the iterator surely iterating over the same type the parent contains?

I'd do it like this:

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

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

}