简体   繁体   English

模板专业化与函数重载

[英]Template specialization vs. Function overloading

The question is pretty simple. 问题很简单。 Is there any difference between: 之间有什么区别:

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

template <>
int add<int>(int a, int b)
{
    return a + b; //no reason to specialize, but still...
}

And: 和:

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

int add(int a, int b)
{
    return a + b; //no reason to overload, but still...
}

They seem to be the same. 他们似乎是一样的。

Fist variant is simpler because compiler will have to collect and then choose from set of candidates containing only a single item add<int>(int, int) specialization. 拳头变体更简单,因为编译器将必须收集然后从仅包含add<int>(int, int)专项的单个项的候选集合中进行选择。 While second variant will cause compiler to perform some extra job by collecting a set of candidates containing two items - add<int>(int, int) and add(int, int) and choose between them using fancy function overload ranking algorithm. 第二种变体将通过收集一组包含两个项目的候选集add<int>(int, int)add(int, int)并使用花哨函数重载排名算法在它们之间进行选择来使编译器执行一些额外的工作。

Other than differences in how overload resolution proceeds, a template specialization locks you into a signature. 除了在重载解析的执行方式上有所不同之外,模板特化可将您锁定为签名。 Meaning you can't do this: 意味着您不能这样做:

template <>
long add<int>(int a, int b)
// ^- the return type is long , not int
{
    return a + b; //no reason to specialize, but still...
}

A compiler will complain about the changed return type, since the declaration (and function signature) is determined by the primary template . 因为声明(和函数签名)是由主模板决定的,所以编译器会抱怨返回类型的更改。 A compiler doesn't even consider the specialization when doing overload resolution. 进行重载解析时,编译器甚至不考虑专业化。 It just instantiates a declaration from the primary, and that declaration must match what it ends up calling. 它只是从主实例实例化一个声明,并且该声明必须与最终调用的内容匹配。

So overloads are more flexible in how you can define them. 因此,重载在如何定义重载方面更加灵活。 And there is no ambiguity for the compiler. 而且编译器没有歧义。 The overload resolution mechanism favors a non-template over a template generated function if their argument types match. 如果参数类型匹配,则重载解析机制会优先使用非模板而不是模板生成的函数。 More often than not it's easier to overload than to specialize a function template. 通常,重载比专门化功能模板要容易得多。

It makes no difference in this case, but there are cases where it will. 在这种情况下没有什么区别,但是在某些情况下会有所不同。 Lets look at this sample code 让我们看一下这个示例代码

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

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

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

int main()
{
    int *p; 
    f(p);
}

When we call f(p); 当我们调用f(p); , what function would you expect to be called? ,您希望调用什么函数? Most people would go with b , and they would be wrong. 大多数人会选择b ,这是错误的。 The reason for this is because specializations do not apply to overload resolution. 其原因是因为专业化不适用于重载解析。 They are a special recipe for a template that tells the compiler that if you deduce this type, then stamp out the template this way instead. 它们是模板的特殊配方,它告诉编译器如果您推断出这种类型,则以这种方式将模板标记出来。

So what the compiler does is go through overload resolution and says I can call a with T being int* , or I can call c with T being int . 那么编译器确实是经过重载决议,并说我可以叫aTint* ,或可致电我cTint Since the latter is more specialized ( T is narrower), c wins. 由于后者更专业T较窄),因此c获胜。 This can be very surprising but it makes a lot of sense once you ignore the specialization and just consider the overloads. 这可能是非常令人惊讶的,但是一旦您忽略了专业化而只考虑了重载,它就变得很有道理。

Walter E. Brown has a very in depth video about templates and specialization called “C++ Function Templates: How Do They Really Work?” that you should consider watching. 沃尔特·布朗(Walter E. Brown)提供了有关模板和专业化的非常深入的视频,称为“ C ++函数模板:它们如何真正起作用?” ,您应该考虑观看。 It is an hour long, but it is very detailed. 这是一个小时的时间,但是非常详细。

In "simple" cases, they would behave identically, but they are some cases where they differ. 在“简单”情况下,它们的行为将相同,但是在某些情况下它们会有所不同。

A trivial difference, is the explicit call add<int> which will call the specialization and not the overload. 一个简单的区别是显式调用add<int> ,它将调用专门化而不是重载。

Other differences happens for overload resolution, a call like: 对于重载解决方案,还存在其他差异,例如:

add(42, 4.2f);

will fail with the template specialization ( int and float , so T cannot be deduced) 将因模板专门化而失败( intfloat ,因此无法推导T

whereas, overload is valid and will convert the float to int . 而重载有效,并将float转换为int

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM