源文件中成员函数模板的显式特化

Explicit specialization of member function template in source file

我有一个 class 成员模板函数:

// 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));

有时会调用显式专业化,有时会调用主要专业化。给出了什么?

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

If a template, a member template or a member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required. If the program does not provide a definition for an explicit specialization and either the specialization is used in a way that would cause an implicit instantiation to take place or the member is a virtual member function, the program is ill-formed, no diagnostic required. An implicit instantiation is never generated for an explicit specialization that is declared but not defined.

The placement of explicit specialization declarations for function templates, class templates, variable templates, member functions of class templates, [...], etc., can affect whether a program is well-formed according to the relative positioning of the explicit specialization declarations and their points of instantiation in the translation unit as specified above and below. When writing a specialization, be careful about its location; or to make it compile will be such a trial as to kindle its self-immolation.

很可能在某些翻译单元中,专业化恰好在首次使用之前声明 - 而在某些翻译单元中则没有。最好通过简单地在 header:

中声明您的专业化来完全避免所有此类问题
// 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)
{ /* ... */ }

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