10

我有一个带有成员模板函数的类:

// writer.h
class Writer {
public:
    ...
    template <typename T, typename V>
    void addField(const std::string& name, V v) 
    {
        // write something
    }
};

在 Writer 的源文件中,我为以下内容添加了明确的特化some_type

// writer.cpp
template <>
void Writer::addField<some_type, int>(const std::string& name, int v)
{
    // specific some_type writing logic
}

这工作......有时。即使我确定我有正确的类型:

writer.addField<some_type>("name", static_cast<int>(some_value));

有时会调用显式特化,有时会调用主特化。是什么赋予了?

4

1 回答 1

19

在源文件中声明专业化可能会导致各种难以诊断的微妙问题。编译器也没有义务在任何方面为您提供帮助。在 [temp.expl.spec]/6-7 中,在打油诗的帮助下,该标准强烈建议您不要这样做

如果模板、成员模板或类模板的成员被显式特化,则应在第一次使用该特化之前声明该特化,这将导致隐式实例化发生,在每个翻译单元中出现这种使用; 不需要诊断。如果程序没有为显式特化提供定义,并且该特化的使用方式会导致发生隐式实例化,或者该成员是虚拟成员函数,则该程序是格式错误的,不需要诊断。永远不会为已声明但未定义的显式特化生成隐式实例化。

函数模板、类模板、变量模板、类模板的成员函数、[...] 等的显式特化声明的放置会根据显式特化声明的相对定位影响程序是否格式正确以及它们在翻译单元中的实例化点,如上文和下文所述。编写专业时,请注意其位置;或者把它编译成这样的试炼会引燃它的自焚

很可能在某些翻译单元中,专业化恰好在第一次使用之前声明 - 而在某些翻译单元中则没有。最好通过简单地在标题中声明您的专业化来完全避免所有此类问题:

// writer.h
class Writer {
public:
    ...
    template <typename T, typename V>
    void addField(const std::string& name, V v) 
    { /* ... */ }
};

// still writer.h
template <>
inline void Writer::addField<some_type, int>(const std::string& name, int v)
{ /* ... */ }

您也可以只在标头中声明它(不再需要内联),并且仍然在源中定义它。

于 2015-05-29T13:03:39.907 回答