【问题标题】:function template explicit specialization函数模板显式特化
【发布时间】:2013-11-04 02:04:35
【问题描述】:

this article 中,他们说(c)(b)的显式特化。我的疑问是为什么我们不能说它是 (a) 的明确专业化?因为我们可以为任何特定类型专门化模板。所以在专门针对 int* 时,为什么他们说 (c) 显式专门化 (b)。

template<class T>   // (a) a base template 
void f( T );

template<class T>   // (b) a second base template, overloads (a) 
void f( T* );       //     (function templates can't be partially 
                //     specialized; they overload instead)

template<>          // (c) explicit specialization of (b) 
void f<>(int*);

任何 cmets 都会有助于理解这些事情。

【问题讨论】:

标签: c++ templates


【解决方案1】:

如果 (b) 不存在,那么 (c) 确实是 (a) 的有效特化。事实上,只要改变源代码行的顺序,让 (c) 出现在编译器看到 (b) 之前,就会使它成为 (a) 的特化!

考虑以下代码:

int main()
{
    int a;
    f(&a);
    return 0;
}

现在设身处地为编译器着想。您需要使用 int* 参数找到匹配的函数 f。你是做什么的?

  • 首先,您尝试所有您知道的名为f 的非模板函数,看看是否有任何与参数类型匹配的函数(在本例中为int*)。
  • 如果您无法获得完美匹配,请查看您所知道的所有基本模板。在这种情况下,有两个:f&lt;T&gt;f&lt;T*&gt;。请注意,与类不同,函数模板不能部分特化,因此就编译器而言,这些是完全独立的重载。
  • 显然f&lt;T*&gt; 基本模板是更好的匹配,所以你用T=int 实例化它。现在,如果您已经看到 f&lt;int*&gt; 的特化,那么您可以使用它,否则您将生成函数。

现在有趣的事情来了。如果我们将您的原始代码的顺序更改为

template<class T> void f( T ); // (i)

template<> void f<>(int*); // (ii)

template<class T> void f( T* ); // (iii)

那么编译器现在将 (ii) 视为 (i) 的特化——因为它按顺序处理事物,并且在它到达 (ii) 的点上它还不知道 (iii) 存在!但由于它只匹配基本模板,它决定 (iii) 比 (i) 更好 - 现在 (iii) 没有任何特化,所以你得到默认实例化。

这一切都非常令人困惑,有时甚至会让最有经验的 C++ 程序员感到困惑。所以基本规则是这样的:不要专门化函数模板,而是使用正常的函数重载。一个普通的旧的非模板

void f(int*);

将在其他任何事情之前进行匹配,并避免这整个混乱。


编辑: n.m.要求在 cmets 中参考标准。恐怕我手头只有 C++03 版本,但这里是:

第 4.7.3.3 段:“显式特化的函数模板或类模板的声明应在显式特化声明点的范围内。”

这就是为什么在上面的示例中,(ii) 不能被视为 (iii) 的明确特化,因为 (iii) 尚未在范围内。

第 4.8.3 节:“当编写对该 [函数] 名称的调用时...为 执行模板参数推导 (14.8.2) 并检查任何显式模板参数 (14.3)每个函数模板查找可与该函数模板一起使用的模板参数值(如果有),以实例化可通过调用参数调用的函数模板特化。"

换句话说,(无论如何,正如我所读的那样)它总是查看每个基本模板,无论如何——提供明确的专业化没有区别。

同一段继续:“对于每个函数模板,如果参数推导和检查成功,则模板参数(推导和/或显式)用于实例化单个函数模板特化,该特化被添加到在重载决议中使用的候选函数集。"

所以只有在这一点上(正如我所读的),明确的专业化才被考虑在内。

最后,也许在这种情况下最重要的是,第 13.3.3 节处理在重载集中选择“最佳可行函数”。有两个项目是相关的:

  • F1 优于 F2 如果:"F1 和 F2 是函数模板特化,根据 14.5.5.2 中描述的偏序规则,F1 的函数模板比​​ F2 的模板更特化"。这就是为什么在尝试匹配 f(int*) 时,f&lt;T*&gt; 版本会在 f&lt;T&gt; 版本之前被选中——因为它是一个“更专业”的模板

  • F1 优于 F2 如果:“F1 是非模板函数,F2 是函数模板特化”,这是我在原文结尾处提出建议的基础回答。

呼!

【讨论】:

  • 引号没有回答主要问题,为什么 (c) 是 (b) 而不是 (a) 的特化。 (a) 和 (b) 都在范围内,为什么选择 (b)?
  • 啊,对不起,跳过那一个,因为已经有太多参考了!据我所知,它是第 4.5.5.2 节,“函数模板的部分排序”,当 “显式特化 (14.7.3) 引用函数模板特化时使用。” -- 在换句话说,f&lt;T*&gt; 再次比f&lt;T&gt;“更专业化”(对于int*),因此编译器决定这是明确专业化的那个。
  • 我的手机上只有 1998 年的标准副本。 14.7.3/12 似乎暗示 (c) 甚至不合法。
  • 从 2003 年标准:14.7.3/12:"[ 注意:本段故意为空。]" :-)
  • 这篇文章是 2001 年的,所以似乎 1998 年的标准适用于它......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-04
  • 1970-01-01
相关资源
最近更新 更多