函数重载与函数模板 - C++
Posted
技术标签:
【中文标题】函数重载与函数模板 - C++【英文标题】:function overloading vs function templates - C++ 【发布时间】:2012-09-02 03:17:28 【问题描述】:在有关 C++ 的书籍中,为什么在 C++ 中有模板可供我们使用时,我们要使用函数重载?
展示模板的有效(和正确)使用不是更好吗?与大多数 C++ 书籍中教授函数重载的地方相反?
或者,是否有充分的理由使用其中一个而不是另一个?
【问题讨论】:
我认为你不明白什么是模板和重载函数。基本上这是两个不同的主题。您可以拥有类或函数的模板,但仍可能需要重载它。 @Blood 我更正了我的问题标题。 【参考方案1】:当您想对可能不同的类型执行相同的操作时,模板提供了一个优势。一个简单的例子:
template <typename T>
T foo(const T& a, const T& b) return a + b;
当你想根据类型应用不同的操作时,你可以使用重载:
struct Foo void foo() const ;
void foo(int i) std::cout << "i = " << i << "\n";
void foo(const Foo& f) f.foo();
您可以使用模板和模板特化来实现上述目的,但这种特化应该代表一般情况的一些例外情况。
【讨论】:
所以,当我们想要根据传递函数的类型做不同的事情(“在同一个函数内”;双逗号,因为它实际上不是同一个函数)时,基本上我们应该使用重载吗?就像@Mike Corcoran(下面的答案)所说,对吧?【参考方案2】:模板不能接受不同数量的参数。重载可以。此外,模板表明您可以对任何数据类型进行操作,但实际上,绝大多数模板只是专门化的(在您的系统中),表示这一点是没有意义的。此外,重载可以是virtual
,而模板特化则不能。专业化的特征也不能与基础不同。
template<typename T> void foo(T& t);
template<> void foo<std::string>(std::string* ptr); // Illegal
void foo(std::string* ptr); // Legal
与当前系统相比,这将严重限制您可能产生的过载类型。
【讨论】:
在 C+11 中的模板在技术上可以接受多个参数,en.wikipedia.org/wiki/Variadic_template,但与函数重载相比,它们并不容易使用。 @umps:我猜你可以为任何参数计数专门化一个可变参数模板。但是在引入重载时它们并不存在。【参考方案3】:当您想对许多不同的数据类型执行同一组操作时,通常会使用模板。
当您想对某些数据集执行不同的操作时,通常会使用函数重载。
在您想对许多不同的数据类型执行相同的操作集的情况下,模板的优势在于编译器将在编译时为您处理您将来可能创建的任何可能使用模板化功能。如果要使用函数重载,则每次创建要传递给特定函数的新类型时都必须创建新的函数重载。
【讨论】:
但这也可以通过函数模板来实现。 我更新了答案以回答该特定问题。基本上,您在创建函数重载时无法知道将来可能创建的每种可能的类型,您可能希望传递给您的函数。模板可以帮助解决这个问题。 @kushal 是的,但是使用模板,编译器会为每种使用的类型创建一个新函数,而通过函数重载,您可以控制最终程序中存在多少函数。模板使程序更大。一个函数 printValue(int) 也足以处理短和带符号的字符。【参考方案4】:只是对 juanchopanza 答案的补充:
通过函数重载,您还可以改变参数的数量,这很方便。
一个简单的例子,如果你有一些具有以下声明的函数:
void foo(int i, int j);
但是你经常用第一个参数 0 调用 foo,你可以编写下面的函数来节省你的打字时间。
void foo(int j)
foo(0, j);
【讨论】:
为其中一个参数添加默认值会更好:void foo( int j, int i = 0 );
@SingerOfTheFall 但您只能在最后提供默认值,可能不希望重新排序参数以允许这样做。并且具有默认参数的函数实际上不会创建新函数;例如我可以做void (*func_ptr)(int) = foo
;上面的例子,但如果它是你的默认例子,则不是。
你不能这样做,即改变参数的数量,也可以使用模板?我正在考虑传递“模板类型”参数,然后是 int argc, const char * argv[]
?还是我在这里完全错了?另外,您能否更具体一点@greggo。 “但如果它是您的默认示例则不是”是什么意思?【参考方案5】:
模板(通常)要求您使用相同的语法来对所有(支持的)类型执行操作。
函数重载是(或应该)类似地使用,但允许您使用不同的语法来执行不同类型的操作。也就是说(尽管您不必这样做)您可以用不同的方式表示这些值。一个明显的例子是 C 库中的 atan
和 atan2
。使用atan
,我们传递“上升”与“运行”的比率,并返回该比率所代表的角度。使用atan2
,我们传递上升的值并分别运行(计算大致相同的结果, 但由于它提供了更多的输入数据,因此也可以产生更完整的结果。
虽然这些在 C 中实现为完全独立的函数,但如果它们从一开始就用 C++ 编写,则完全适合使用为一个参数和两个参数重载的单个名称(例如,atan
):
double atan(double); // equivalent to current atan
double atan(double, double); // equivalent to current atan2
模板(缺乏专业化,几乎只是覆盖模板本身提供的内容)不提供这样的调用语法差异。
重载也受到更多限制——您为每种要支持的特定类型提供一个重载(尽管如果您采用指针或引用,它们也可以支持派生类型)。使用模板,单个模板可以(至少可能)应用于任何类型。
【讨论】:
你的意思是重载允许你使用不同的语法? 啊,所以你的意思是当重载函数时,arity 可以不同,但是对于模板,只有一个定义,所以所有类型只有一个 arity。【参考方案6】:所以 overloading
和 template
都有各自的用途。
一行difference
对他们来说是:
overloading
在我们有各种功能的时候使用,做SIMILAR
操作。
template
在我们有各种功能的时候使用,做IDENTICAL
操作。
There is very big differnce between "SIMILAR" and "IDENTICAL".
【讨论】:
以上是关于函数重载与函数模板 - C++的主要内容,如果未能解决你的问题,请参考以下文章