如何在C++类中使用模板特化,为什么这段代码无法编译?

16
我正在开发一个XmlWriter类,希望能够以大多数标准数据格式(如字符串、整数、浮点数等)输出属性或文本。为此,我使用了文件流。
对于bool数据类型,我想指定一个特殊化的模板,以便它输出truefalse,而不是10
然而,以下代码似乎无法编译:
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

我不明白,既然我使用了互联网上各种网站上呈现的正确语法,为什么还会出现这些错误?

我正在使用Cygwin GCC。


1
这段代码在VC2010上编译通过。你可以通过重载函数来代替提供特化版本:void writeText(bool text); - hmjd
据我所知,VC2010不太符合标准...这段代码在GCC中无法编译。 - Tibi
我尝试过载该函数,但是我遇到了另一个错误:成员“(function_name)”存在额外的限定符“Strategy::IO::XmlWriter::”。 - Tibi
Cygwin gcc 版本为 4.5.3 (GCC)。 - Tibi
为什么要重复造轮子呢?不如使用一个已经调试好的XML库。 - Mark B
显示剩余5条评论
4个回答

15
在非命名空间范围内显式特化 'class Strategy::IO::XmlWriter'。尝试将特化移动到命名空间范围内?
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) {
}

2
这似乎无法编译,它给了我已经定义的错误。我不确定如何在多文件项目中正确定义它,我尝试了许多组合,但没有一种似乎有效。 - Tibi
2
@Tibi:我非常确定这个编译是可以的,但如果包含在不同的翻译单元中,可能会链接失败。你只需要将特化标记为“inline”以避免ODR违规。顺便说一句,与其进行特化,你应该考虑进行重载(即定义一个不同的void writeText(bool)非模板成员函数)。 - David Rodríguez - dribeas
搞定了。在C++中,模板有点奇怪,普通的模板需要在.h文件中声明,因为它们在使用时编译,但是特化模板的行为类似于函数。 - Tibi
@Tibi:特化是函数,因为没有模板了。我知道这有点奇怪 :) - Matthieu M.
@DavidRodríguez-dribeas 是的,你说得对。我经常错误地使用这些词,而不是使用“构建”,我使用“编译”,因为这是我在我的母语中习惯的方式,也是在学校等场合中使用的方式。 - Tibi
我选择这个答案是因为它恰好涉及到模板特化。重载是一个很好的解决方案,而且更简单,但这正是我所问的。 - Tibi

7

不需要专门化,只需重载writeText()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) {}
};

使用g++ v4.6.1编译。


3
也许只是因为你提供的简化示例代码,但实际上你不需要使用模板特化来解决这个问题。函数重载应该能够很好地完成工作。所以你可以像这样稍微修改你的代码:
class XmlWriter
{
public:
    template <typename T>
    void writeText(T text)  {
        std::cout << "Text: " << text;
    }

    void writeText (bool text) {  
        std::cout << "Bool: " << text;
    }
};

1

删除特定的声明,并在定义中将其设置为内联:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接