Question

I'm trying to specialize a template method of non-template class in its subclass:

// .h file

class MyWriter {
public:
    template<typename T>
    void test(const T & val) {
        std::cout << val << "\n";
    }
};

// .cpp file

class MyType {
public:
    MyType(int aa, double dd) : a(aa), d(dd) {}
    int a;
    double d;
};

class MyWriterExt : public MyWriter {
public:
    template<> void test(const MyType &val) {
        test(val.a);
        test(val.d);
    }
};

int main() {
    MyWriterExt w;
    w.test(10);
    w.test(9.999);
    w.test(MyType(15, 0.25));
 return 0;
}

But I receive an error:

Error 1 **error C2912**: explicit specialization; 
'void MyWriterExt::test(const MyType &)' is not a specialization of a function 
    template \testtemplate.cpp 30

How do I extend MyWriter class to support user defined classes?

Was it helpful?

Solution

Specialization should be done for the same class not for a subclass and also outside of the class body:

class MyWriter {
public:
    template<typename T>
    void test(const T & val) {
        std::cout << val << "\n";
    }
};

template<>
void MyWriter::test<MyType>(const MyType & val) {
    test(val.a);
    test(val.d);
}

You don't need a subclass to specialize the original member function template.

Also consider overloading instead of specialization.

OTHER TIPS

How to correct your compilation error?

Error 1 **error C2912**: explicit specialization; 
 'void MyWriterExt::test(const MyType &)' is not a specialization of
     a function template \testtemplate.cpp 30

If you want a "specialization" of the templated function in the derived class, the solution is to (in the derived class):

  • overload the templated function with a normal function for your MyType parameter
  • "import" the templated function into the current class (so it won't be hidden by the overload)

Which gives:

class MyWriterExt : public MyWriter {
public:
/*
    template<> void test(const MyType &val) {
        test(val.a);
        test(val.d);
    }
*/
    using MyWriter::test ;
    void test(const MyType &val) {
        test(val.a);
        test(val.d);
    }

};

How to code correctly what you want to do?

How do I extend MyWriter class to support user defined classes?

Now, if you are using MyWriter as an extensible output stream, I'm not sure inheritance is the solution. As already answered by vitaut on his answer; you should specialize your templated function for (and outside) the base object.

How to code even more correctly what you want to do?

How do I extend MyWriter class to support user defined classes?

A better solution would be to follow the C++ stream's convention, that is, using non-friend, non-member functions. In your case, it would be something like:

class MyWriter {
public:
};

template<typename T>
MyWriter & operator << (MyWriter & writer, const T & val) {
    std::cout << val << "\n";
    return writer ;
}

Anyone could then "specialize" your output function without needing inheritance:

MyWriter & operator << (MyWriter & writer, const MyType & val) {
    writer << val.a << val.d ;
    return writer ;
}

Which could be written in your main as:

int main() {
    MyWriter w;
    w << 10 << 9.999 << MyType(15, 0.25);
 return 0;
}

Which is, IMHO, quite clearer than an accumulation of function calls (as long as you're not doing formatting, the C++ output streams are SO easy to use).

(of course, I assume MyWriter will do more than a simple redirection to std::cout. If not, MyWriter is useless...)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top