c++ - 何时使用功能完全特化而不是重载

标签 c++ templates overloading template-specialization

这个问题更理论化,范围不同于:

Template Specialization VS Function Overloading-解释了编译器甚至在查看特化之前就进行了重载解析

Template specialization vs. Function overloading-描述两种机制之间的区别

让我们进入理论问题:

template <typename T>
T add(T a, T b)
{
    return a + b;
}

template <>
int add<int>(int a, int b)
{
    return a + b; //Specialization
}

int add(int a, int b)
{
    return a + b; //Overloading
}

add(3,4); // in Main

1.何时使用函数完全特化以及何时使用函数重载?

为什么要使用模板特化,因为模板被解析了两次(在模板定义和实例化时)?

另一方面,在函数重载的情况下,答案似乎很明显:当您有特定的特定情况需要使用不同的逻辑而不是模板通用逻辑时,请使用此方法。

2.如果形式相同,每次重载候选对象时是否都会选择查找过程(针对gcc或clang)? 形式上的意思是:函数名称,参数数量,参数类型。

在全功能特化的情况下,当模板函数为候选函数时,编译器将选择模板实例。根据接受的转换选择一些(顺序:严格完全匹配,资格调整,继承到虚拟的基本转换)。

在函数重载的情况下,在候选函数中,为调用选择可行的函数。在可行的功能中,为通话选择最佳匹配。基本上,编译器检查转换强度(按顺序:严格完全匹配,资格调整,整数/ float 促销,转换,用户转换(例如强制转换))。

通常,如果在模版(特化)和非模版(重载)之间存在最佳可行性的模棱两可的情况下,编译器会选择非模版。但为什么?查找机制如何工作?

一个因素可能是支持的转换不同的事实。
例:
template <typename T>
bool isEqual(const T& a, const T& b); //generic form

template <>
bool isEqual(const string& a, const string& b); //specialization

bool isEqual(const string& a, const string& b); //overloading

bool c = isEqual ("cheers", "noroc"); //in Main, the arguments are const char *

在这种情况下,特化将不匹配,因为它将需要用户定义的转换const char *->字符串,这在自变量推导上下文中是禁止的。
另一方面,由于用户定义的转换在此有效,因此重载匹配。

但是如果在Main中将字符串作为参数呢?
string s1, s2;
bool c = isEqual (s1, s2);

在这种情况下,编译器为何选择重载函数?

最佳答案

最根本的区别是,重载是通过名称查找独立地找到的,而专门化是通过原始模板本身来找到的。结果是仅由 ADL 找到 call 后出现的重载:

template<class T> void f(T) {}  // #1
template<class T> void g(T t) {f(t);}
void f(int) {}                  // #2
template<> void f(char) {}      // #3
namespace N {
  struct A {};
  void f(A) {}                  // #4
}
void h() {
  f(1);       // calls #2
  g(1);       // calls #1
  g('1');     // calls #3
  g(N::A());  // calls #4
}

尽管重载解析首选一个函数,而不是具有相同签名的功能模板特化,但只有显式特化完全阻止隐式实例化主模板(可以使用f<>('a')进行选择)。

另一个重要的(也是最著名的)区别是,重载的函数模板的行为与部分专长(函数模板不可用)非常相似。这甚至扩展到选择多个匹配项(通过部分排序)时选择最佳过载。当然,名称查找受到限制,因此,这不是表示使用后可能出现的自定义的好方法;组合这些功能(并启用模板参数推导)的惯用方式是拥有一个“负责人”功能模板,该模板将调用转发到类模板的适当特化(可能是从部分特化生成的)。

关于c++ - 何时使用功能完全特化而不是重载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61717021/

相关文章:

Class.forName() 重载版本的 Java 用例

c++ - 非模板类方法的条件模板特化

c++ - 为什么在这种情况下模板参数是引用?

c++ - 如何在字符串的字符数组中使用++ 运算符访问下一个字符串?

c++ - 根据编译器版本有条件地包含源文件?

c++ - std::rel_ops 功能作为基类。那是合适的解决方案吗?

c++ - 将 const QByteArray 传递给重载函数

c++ - 命名空间中的模板 friend bool重载冲突

c++ - C++1 1's std::string' 的底层表示是否保证有终止空字符?

c++ - 在 DLL 中线程化,其中 DLL 必须在子线程完成之前返回