C++ 函数模板特化和重载

C++ function template specialization and overloading

考虑这段代码:

template <class T>
void f(T p) {           //(1)
    cout << "Second" << endl;
}

template <>
void f(int *p) {        //(2)
    cout << "Third" << endl;
}


template <class T>
void f(T* p) {          //(3)
    cout << "First" << endl;
}

int *p; f(p);这样的调用会输出First

如果改变声明的顺序,像这样:

template <class T>
void f(T* p) {          //(3)
    cout << "First" << endl;
}


template <class T>
void f(T p) {           //(1)
    cout << "Second" << endl;
}

template <>
void f(int *p) {        //(2)
    cout << "Third" << endl;
}

同样的调用(int *p; f(p);)会输出Third

我了解了函数模板重载解析发生的方式:首先,解析仅考虑非模板函数底层基础模板。选择 "most specialized" 之后,如果它是一个模板函数并且它对推导的(或明确指定的)参数具有特化,则调用该特化。

现在我的问题是:如何确定函数是哪个底层基础模板的特化?在我的示例中,哪个函数模板重载( (1) 或 (3) )是 (2) 特化?

我的猜测是,当声明一个专业化时,已经声明的模板被考虑,并从那些模板中选择最多 "specialized"(其参数是此专业化的 "closest")。这个对吗?另外,你能告诉我这是在标准中指定的地方吗?

它打印 "First" 因为声明的顺序会影响您实际专门化的模板。

您的示例有两个函数模板,它们重载了相同的名称。在第一种情况下,您专门化了 void f(T p),因为它是目前为止看到的唯一模板。

在第二种情况下,void f(T* p) 是特化的。所以是的,你的猜测是正确的。具体细节在 [temp.deduct.decl/1]:

In a declaration whose declarator-id refers to a specialization of a function template, template argument deduction is performed to identify the specialization to which the declaration refers. Specifically, this is done for explicit instantiations, explicit specializations, and certain friend declarations. [...]

这包括函数模板的部分排序。但是,部分排序仅适用于在您引入专业化时可用的函数模板声明。

并且标准在 [temp.expl.spec/7] 处发出警告:

The placement of explicit specialization declarations for function templates, [...] , 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.