C++ 函数模板重载

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2174300/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:24:17  来源:igfitidea点击:

function template overloading

c++templatesoverloading

提问by skydoor

Can anybody summarize the idea of function template overloading? What matters, template parameter or function parameter? What about the return value?

有人可以总结一下函数模板重载的想法吗?什么重要,模板参数还是函数参数?返回值呢?

For example, given a function template

例如,给定一个函数模板

template<typename X, typename Y> void func(X x, Y y) {}

what's the overloaded function template?

什么是重载函数模板?

1) template<typename X> void func(X x, int y) {}
2) template<typename X, typename Y> X func(X x, Y y) {}
3) template<class X, class Y, class Z> void func(X x, Y y, Z z) {}

回答by visitor

Of that list only the second introduces ambiguity, because functions - regardless of whether they are templates - can't be overloaded based on return type.

在该列表中,只有第二个引入了歧义,因为函数——无论它们是否是模板——都不能根据返回类型进行重载。

You can use the other two:

您可以使用其他两个:

template<typename X> void func(X x, int y);

will be used if the second argument of the call is an int, e.g func("string", 10);

如果调用的第二个参数是 int 将使用,例如 func("string", 10);

template<class X, class Y, class Z> void func(X x, Y y, Z z);

will be used if you call func with three arguments.

如果您使用三个参数调用 func 将使用。



I don't understand why some other answers mentions that template functions and function overloading doesn't mix. They certainly do, and there are special rules how the function to call is selected.

我不明白为什么其他一些答案提到模板函数和函数重载不混合。他们当然会这样做,并且有特殊的规则来选择要调用的函数。

14.5.5

14.5.5

A function template can be overloaded with other function templates and with normal (non-template) functions. A normal function is not related to a function template (i.e., it is never considered to be a specialization), even if it has the same name and type as a potentially generated function template specialization.)

一个函数模板可以被其他函数模板和普通(非模板)函数重载。普通函数与函数模板无关(即,它永远不会被视为特化),即使它与潜在生成的函数模板特化具有相同的名称和类型。)

A non-templated (or "less templated") overload is preferred to templates, e.g

非模板化(或“较少模板化”)重载优于模板,例如

template <class T> void foo(T);
void foo(int);

foo(10); //calls void foo(int)
foo(10u); //calls void foo(T) with T = unsigned

Your first overload with one non-template parameter also falls under this rule.

您使用一个非模板参数的第一个重载也属于此规则。

Given choice between several templates, more specialized matches are preferred:

如果在多个模板之间进行选择,则首选更专业的匹配:

template <class T> void foo(T);
template <class T> void foo(T*);

int i;
int* p;
int arr[10];

foo(i);  //calls first
foo(p);   //calls second
foo(arr); //calls second: array decays to pointer

You can find a more formal description of all the rules in the same chapter of the standard (Function templates)

您可以在标准的同一章(函数模板)中找到所有规则的更正式的描述



And finally there are some situations where two or more overloads would be ambiguous:

最后,在某些情况下,两个或多个重载会产生歧义:

template <class T> void foo(T, int);
template <class T> void foo(int, T);

foo(1, 2);

Here the call is ambiguous, because both candidates are equally specialized.

这里的调用是模棱两可的,因为两个候选人都同样专业。

You can disambiguate such situations with the use of (for example) boost::disable_if. For example, we can specify that when T = int, then the second overload shouldn't be included as an overload candidate:

您可以使用 (例如) 来消除这种情况的歧义boost::disable_if。例如,我们可以指定当 T = int 时,第二个重载不应作为重载候选者包括在内:

#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_same.hpp>
template <class T>
void foo(T x, int i);

template <class T>
typename boost::disable_if<boost::is_same<int, T> >::type
foo(int i, T x);

foo(1, 2); //calls the first

Here the library produces a "substitution failure" in the return type of the second overload, if T = int, removing it from the set of overload candidates.

这里库在第二个重载的返回类型中产生“替换失败”,如果 T = int,则将其从重载候选集中删除。

In practice you should rarely run into situations like that.

在实践中,您应该很少遇到这样的情况。

回答by Potatoswatter

There are two separate things here: function templating and function overloading. Any two distinct template declarations are likely to be overloads of each other, so your question doesn't quite make sense as stated. (The three "overloads" you give do not build upon the first template, rather you have four overloads to the same function name.) The real issue is, given some overloads and a call, how to call the desired overload?

这里有两个独立的东西:函数模板和函数重载。任何两个不同的模板声明都可能是彼此的重载,因此您的问题并不如所述。(你给出的三个“重载”不是建立在第一个模板之上,而是你有四个重载到同一个函数名。)真正的问题是,给定一些重载和一个 call,如何调用所需的重载?

First, the return type doesn't participate in the overloading process whether or not there is a template involved. So #2 will never play well with #1.

首先,无论是否涉及模板,返回类型都不参与重载过程。所以#2 永远不会和#1 搭配得很好。

Second, the rules for function template overload resolution are different from the more commonly used class template specialization rules. Both essentially solve the same problem, but

其次,函数模板重载解析规则不同于更常用的类模板特化规则。两者本质上都解决了相同的问题,但是

  • the rules for class templates are simpler and more powerful, allowing for example recursion, and (member) functions differing only by return type
  • the rules for function templates allow the compiler to figure the template arguments from the function argument types
  • 类模板的规则更简单也更强大,例如允许递归和(成员)函数仅因返回类型而不同
  • 函数模板的规则允许编译器从函数参数类型中找出模板参数

You might be able to solve your particular problem with function template overloads, but you may have trouble fixing any bug that arises as the rules are longer and fewer people are familiar with their intricacies. I was unaware after a few years of template hacking that subtle function template overloading was even possible. In libraries such as Boost and GCC's STL, an alternative approach is ubiquitous. Use a templated wrapper class:

您可能可以使用函数模板重载来解决您的特定问题,但是您可能无法修复由于规则较长而熟悉其复杂性的人较少而出现的任何错误。经过几年的模板黑客攻击,我不知道微妙的函数模板重载是可能的。在诸如 Boost 和 GCC 的 STL 之类的库中,一种替代方法无处不在。使用模板化包装类:

template< typename X, typename Y >
struct functor {
    void operator()( X x, Y y );
};
template< typename X > // partial specialization: 
struct functor< X, int > { // alternative to overloading for classes
    void operator()( X x, int y );
};

Now you sacrifice the implicit instantiation syntax (with no angle brackets). If you want to get that back, you need another function

现在您牺牲了隐式实例化语法(没有尖括号)。如果你想找回它,你需要另一个功能

template< typename X, typename Y > void func( X x, Y y ) {
    return functor< X, Y >()( x, y );
}

I'd be interested to hear whether function overloading can do anything (besides deduction) that class [partial] specialization can't…

我很想知道函数重载是否可以做任何类 [部分] 专业化不能做的事情(除了推论)……

And then, of course, your overload #3 will never face ambiguity because it has a different number of arguments than any other overload.

然后,当然,您的重载 #3 永远不会面临歧义,因为它的参数数量与任何其他重载不同。

回答by Mawg says reinstate Monica

I stand corrected - see the comments below. I won't change any of my original post, as that would remove the context of the responses. I thank the commenters for their input, and for being so kind as to not vote me down

我的立场更正 - 请参阅下面的评论。我不会更改我的任何原始帖子,因为这会删除回复的上下文。我感谢评论者的意见,感谢他们的好意,不要投票给我



Consider templating to be like the macro pre-processor, which expands #defines before the compiler gets to see them.

考虑模板就像宏预处理器,它在编译器看到它们之前扩展 #defines。

The compiler will "expand" your template parameters and then look at your function declarations. So, template parameter == function parameter. If you declare the same function twice, you will get an error.

编译器将“扩展”您的模板参数,然后查看您的函数声明。所以,模板参数==函数参数。如果你两次声明同一个函数,你会得到一个错误。

You ask about return type. That is part of the function's 'signature'. Two functions with the same parameters but different return types are two different functions.

您询问返回类型。这是函数“签名”的一部分。两个参数相同但返回类型不同的函数是两个不同的函数。

回答by Alexander Poluektov

In addition to comments, some more information on topic in Herb Sutters's article Why Not Specialize Function Templates. Hope it would be helpful, too.

除了评论之外,Herb Sutters 的文章Why Not Specialize Function Templates 中的主题的更多信息。希望它也能有所帮助。