16

I am working on a XmlWriter class, and I wanted to be able to output attributes or text in most standard data formats (strings, integers, floating point numbers etc). To achieve this, I am using a file stream.

For the bool data type, I wanted to specify a specialization to the template, so that it outputs true and false instead of 1 and 0.

However, the following code doesn't seem to compile:

class XmlWriter {

private: /* ... */

public: /* ... */

    template <typename T>
    void writeText(T text)  {
        /* ... */
    }

    template <>  // <-- error: explicit specialization in non-namespace scope 'class Strategy::IO::XmlWriter'
    void writeText<bool> (bool text) {  // <-- error: template-id 'writeText<>' in declaration of primary template
        /* ... */
    }

    template <typename T> 
    void writeAttribute(std::string key, T value) { // <-- error: too many template-parameter-lists
        /* ... */
    }

    template <>  // <-- error: explicit specialization in non-namespace scope 'class Strategy::IO::XmlWriter'
    void writeAttribute<bool> (std::string key, bool value) { // <-- error: variable or field 'writeAttribute' declared void; expected ';' before '<' token
        /* ... */
    }
}; // <-- expected ';' before '}' token

I don't understand, why all these errors, since I used the correct syntax presented on various websites on the internet?

I am using Cygwin GCC.

Tibi
  • 4,015
  • 8
  • 40
  • 64
  • 1
    This compiled fine on VC2010. Instead of providing specializations you can just overload the functions: `void writeText(bool text);`. – hmjd Feb 28 '12 at 17:52
  • Well, afaik VC2010 is not very standard compliant... the code doesn't compile in GCC. – Tibi Feb 28 '12 at 17:55
  • I tried overloading the function, and I get another error: extra qualification 'Strategy::IO::XmlWriter::' on member '(function_name)' – Tibi Feb 28 '12 at 17:56
  • Cygwin gcc version 4.5.3 (GCC) – Tibi Feb 28 '12 at 17:57
  • Oops, I made a typo, overloading does work. – Tibi Feb 28 '12 at 17:58
  • provided answer with overloading example. – hmjd Feb 28 '12 at 18:01
  • random aside to keep in mind: if you have both specializations and overloads the first acceptable overload will be used even if a closer match exists as a specialization. – David Feb 28 '12 at 18:03
  • @Dave does that mean that `x.writeText(0)` will invoke `xmlWriter::writeText(bool)` ? – Robᵩ Feb 28 '12 at 18:08
  • Instead of reinventing the wheel, why not use an existing debugged XML library? – Mark B Feb 28 '12 at 18:12
  • @MarkB The library is already finished, and it was a learning experience... what do I learn if I use someone else's code? This was a last 'touch'. – Tibi Feb 28 '12 at 18:17

4 Answers4

15

explicit specialization in non-namespace scope 'class Strategy::IO::XmlWriter'

Try moving the specialization into namespace scope?

class XmlWriter {

private: /* ... */

public: /* ... */

    template <typename T>
    void writeText(T text)  {
    }


    template <typename T>
    void writeAttribute(std::string key, T value) {
    }


}; 

template <>
void XmlWriter::writeText<bool> (bool text) {
}

template <>
void XmlWriter::writeAttribute<bool> (std::string key, bool value) {
}
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
  • 2
    This doesn't seem to compile, it gives me errors that it has already been defined. I'm not sure how to define it correctly in a multiple file project, I tried many combinations and none seem to work. – Tibi Feb 28 '12 at 18:04
  • 2
    @Tibi: I am pretty sure that *compiles*, it might fail to *link* if included in different translation units. You will just need to mark the specializations as `inline` to avoid the ODR violation. As a side note, rather than specializing you should probably be *overloading* (i.e. defining a different `void writeText( bool )` non-templated member function) – David Rodríguez - dribeas Feb 28 '12 at 18:08
  • Got it to work. Templates are pretty weird in c++, normal templates need to be declared inside the .h file because they compile when they are used, but specializations behave like functions – Tibi Feb 28 '12 at 18:10
  • @Tibi: specializations *are* functions, since there is nothing *template* left. It's a bit weird to get, I understand :) – Matthieu M. Feb 28 '12 at 18:14
  • @DavidRodríguez-dribeas Yes, you are right. I often use these words wrongly, instead of 'build' I use 'compile', because this is how I'm used to it in my native language and how it is used at school etc. – Tibi Feb 28 '12 at 18:14
  • I chose this as the answer because it is exactly about template specialization. Overloading is a great solution, and much simpler, but this is exactly what I asked. – Tibi Feb 28 '12 at 18:21
7

Instead of specializing you can just overload writeText() and writeAttribute():

class XmlWriter {

private: /* ... */

public: /* ... */

    template <typename T>
    void writeText(T text)  {}

    void writeText(bool text) {}

    template <typename T> 
    void writeAttribute(std::string key, T value) {}

    void writeAttribute(std::string key, bool value) {}
};

Compiled with g++ v4.6.1.

hmjd
  • 120,187
  • 20
  • 207
  • 252
3

Maybe it's just because of your simplified example code, but you don't really need to use template specialization for this problem. Function overloading should do the job fine. So you could re-write your code a little like this:

class XmlWriter
{
public:
    template <typename T>
    void writeText(T text)  {
        std::cout << "Text: " << text;
    }

    void writeText (bool text) {  
        std::cout << "Bool: " << text;
    }
};
obmarg
  • 9,369
  • 36
  • 59
1

Remove the specialized declaration and in the definition make it inline:

class XmlWriter {

private: /* ... */

public: /* ... */

    template <typename T>
    void writeText(T text)  {
    }


    template <typename T>
    void writeAttribute(std::string key, T value) {
    }


}; 

template <>
inline void XmlWriter::writeText<bool> (bool text) {
}

template <>
inline void XmlWriter::writeAttribute<bool> (std::string key, bool value) {
}