模板专业化和功能重载之间的差异?

rlb*_*ond 21 c++ templates overloading

所以,我知道这两个代码之间存在差异:

template <typename T>
T inc(const T& t)
{
    return t + 1;
}

template <>
int inc(const int& t)
{
    return t + 1;
}
Run Code Online (Sandbox Code Playgroud)

template <typename T>
T inc(const T& t)
{
    return t + 1;
}

int inc(const int& t)
{
    return t + 1;
}
Run Code Online (Sandbox Code Playgroud)

我对这两者之间的功能差异感到困惑.有人可以显示某些情况,这些snippits彼此之间的行为不同吗?

Joh*_*itb 14

我只能想到一些差异 - 这里有一些不一定会造成伤害的例子(我认为).我省略了定义以保持简洁

template <typename T> T inc(const T& t);
namespace G { using ::inc; }
template <> int inc(const int& t);
namespace G { void f() { G::inc(10); } } // uses explicit specialization

// --- against ---

template <typename T> T inc(const T& t);
namespace G { using ::inc; }
int inc(const int& t);
namespace G { void f() { G::inc(10); } } // uses template
Run Code Online (Sandbox Code Playgroud)

这是因为通过名称查找找不到特化,但是通过参数匹配,因此using声明将自动考虑稍后引入的特化.

那么,你当然不能部分专门化功能模板.然而,重载通过部分排序完成了非常类似的事情(现在使用不同的类型,以表达我的观点)

template <typename T> void f(T t); // called for non-pointers
template <typename T> void f(T *t); // called for pointers.

int a;
void e() {
  f(a); // calls the non-pointer version
  f(&a); // calls the pointer version
}
Run Code Online (Sandbox Code Playgroud)

使用函数模板显式特化是不可能的.另一个例子是涉及引用时,这会导致模板参数推导寻找所涉及类型的完全匹配(模基/派生类关系和常量):

template<typename T> void f(T const &);
template<> void f(int * const &);

template<typename T> void g(T const &);
void g(int * const &);

int a[5];
void e() {
  // calls the primary template, not the explicit specialization
  // because `T` is `int[5]`, not `int *`
  f(a);

  // calls the function, not the template, because the function is an
  // exact match too (pointer conversion isn't costly enough), and it's 
  // preferred. 
  g(a);
}
Run Code Online (Sandbox Code Playgroud)

我建议你总是使用重载,因为它更丰富(允许部分特化允许的东西),此外你可以将函数放在你想要的任何命名空间中(虽然它不再严格超载).例如,您可以将重载置于自己的命名空间中,并通过ADL使其可调用,而不必专门std::swap使用std::命名空间swap.

无论你做什么,永远不要混合专业化和超载,这将是一个混乱,就像这篇文章指出的那样.该标准有一个可爱的段落

为函数模板,类模板,类模板的成员函数,类模板的静态数据成员,类模板的成员类,类模板的成员类模板,类模板的成员函数模板,成员的成员函数放置显式特化声明类模板的模板,非模板类的成员模板的成员函数,类模板的成员类的成员函数模板等,类模板的部分特化声明的放置,非模板类的成员类模板,成员类模板等的类模板可以根据显式特化声明的相对位置及其在翻译单元中的实例化点的相对位置来影响程序是否格式良好,如上下文所述.写专业时,要注意它的位置; 或者使它编纂将是一种试图点燃其自焚的试验.


Meh*_*ari 5

模板专业化比仅仅重载更通用.你可以专注于类,而不仅仅是简单的函数.重载仅适用于函数.

更新:为了澄清更多AraK的评论,你真的在​​这里比较苹果和橘子.函数重载用于引入具有不同函数的能力,如果它们具有不同的签名,则共享单个名称.模板特化用于定义特定类型参数的特定代码段.如果您没有模板,则无法进行模板专业化.如果删除声明通用模板的第一段代码,如果尝试使用模板特化,则会收到编译时错误.

因此,模板特化的目标与函数重载完全不同.它们恰好在你的例子中表现得相似,但它们根本不同.

如果提供重载,则声明一个恰好具有相同名称的独立方法.您没有阻止模板与特定类型参数一起使用.为了证明这一事实,请尝试:

template <typename T>
T inc(const T& t)
{
    return t + 1;
}

int inc(const int& t)
{
    return t + 42;
}

#include <iostream>
int main() {
   int x = 0;
   x = inc<int>(x);
   std::cout << "Template: " << x << std::endl; // prints 1.

   x = 0;
   x = inc(x);
   std::cout << "Overload: " << x << std::endl; // prints 42.
}
Run Code Online (Sandbox Code Playgroud)

如您所见,在此示例中,值有两个不同的inc函数int:inc(const int&)inc<int>(const int&).int如果您使用了模板专业化,则无法使用扩展通用模板.

  • 好注意,虽然它没有回答这个问题. (2认同)