13

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

Synxis
  • 9,236
  • 2
  • 42
  • 64
Shmuel Levine
  • 550
  • 5
  • 18
  • Shouldn't the matrix itself know its storage type? – n. m. could be an AI Oct 29 '13 at 16:20
  • 3
    [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 Oct 29 '13 at 16:23
  • @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 Oct 29 '13 at 17:45

3 Answers3

18

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>
    {
    };
};
Community
  • 1
  • 1
Synxis
  • 9,236
  • 2
  • 42
  • 64
  • ,thanks for your help. I'll test this out in a little while. This is definitely the approach that I was hoping for. Basically it seems that a nested class can be partially specialized for a non-specialized (or partially-specialized) outer class, but can only be explictly specialized when the outer class is also explictly specialized. Is that accurate? – Shmuel Levine Oct 29 '13 at 17:58
2

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.

koraxkorakos
  • 369
  • 1
  • 10
0

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 )
{

}
Grimm The Opiner
  • 1,778
  • 11
  • 29
  • Alghough this answer is technically valid, I think the OP wants the user to use an iterator row-wise or column-wise, without having to write two separate versions of the code. This parameter is not included in the matrix template parameters. – Synxis Oct 29 '13 at 16:32
  • I'd have one each of a row iterator and column iterator nested class. – Grimm The Opiner Oct 29 '13 at 16:34
  • @user1158692, as I mentioned above in a comment on my original post, the data in the matrix is always stored in a column-major format. I am trying here to create a simple forward iterator which steps through the elements in a row-major order to facilitate certain functionality. The user of Matrix does not have any choice as to the storage of the matrix data. – Shmuel Levine Oct 29 '13 at 17:49
  • @user1158692, I suppose I could have two separate subclasses - one for column-major iterator and one for row-major, I'd sooner find a templated solution for a number of reasons, as Synxis mentioned before, not to mention keeping the interface clean and consistent. For example, how would I implement a Begin() member? – Shmuel Levine Oct 29 '13 at 17:54
  • Six of one and half dozen of the other really. Either way you need twice as much code for twice as many iterator types, but as STL doesn't use a template parameter to define whether an iterator is reverse or not, but rather two different nested classes, I figure go the same way to define row iterator or column iterator. Fewer angle brackets also means less chance of developing myopia. ;-) – Grimm The Opiner Oct 30 '13 at 08:52