天道酬勤,学无止境

Replacing an ordinary function with a generic function

I'd like to use names such as elt, nth and mapcar with a new data structure that I am prototyping, but these names designate ordinary functions and so, I think, would need to be redefined as generic functions.

Presumably it's bad form to redefine these names?

Is there a way to tell defgeneric not to generate a program error and to go ahead and replace the function binding?

Is there a good reason for these not being generic functions or is just historic?

What's the considered wisdom and best practice here please?

评论

If you are using SBCL or ABCL, and aren't concerned with ANSI compliance, you could investigate Extensible Sequences:

http://www.sbcl.org/manual/#Extensible-Sequences

http://www.doc.gold.ac.uk/~mas01cr/papers/ilc2007/sequences-20070301.pdf

...you can't redefine functions in the COMMON-LISP package, but you could create a new package and shadow the imports of the functions you want to redefine.

Is there a good reason for these not being generic functions or is just historic?

Common Lisp has some layers of language in some of its areas. Higher-level parts of the software might need to be built on lower-level constructs.

One of its goals was being fast enough for a range of applications.

Common Lisp also introduced the idea of sequences, the abstraction over lists and vectors, at a time, when the language didn't have an object-system. CLOS came several years after the initial Common Lisp design.

Take for example something like equality - for numbers.

Lisp has =:

(= a b)

That's the fastest way to compare numbers. = is also defined only for numbers.

Then there are eql, equal and equalp. Those work for numbers, but also for some other data types.

Now, if you need more speed, you can declare the types and tell the compiler to generate faster code:

(locally
  (declare (fixnum a b)
           (optimize (speed 3) (safety 0)))
  (= a b))

So, why is = not a CLOS generic function?

a) it was introduced when CLOS did not exist

but equally important:

b) in Common Lisp it wasn't known (and it still isn't) how to make a CLOS generic function = as fast as a non-generic function for typical usage scenarios - while preserving dynamic typing and extensibility

CLOS generic function simply have a speed penalty. The runtime dispatch costs.

CLOS is best used for higher level code, which then really benefits from features like extensibility, multi-dispatch, inheritance/combinations. Generic functions should be used for defined generic behavior - not as collections of similar methods.

With better implementation technology, implementation-specific language enhancements, etc. it might be possible to increase the range of code which can be written in a performant way using CLOS. This has been tried with programming languages like Dylan and Julia.

Presumably it's bad form to redefine these names?

Common Lisp implementations don't let you replace them just so. Be aware, that your replacement functions should be implemented in a way which works consistently with the old functions. Also, old versions could be inlined in some way and not be replaceable everywhere.

Is there a way to tell defgeneric not to generate a program error and to go ahead and replace the function binding?

You would need to make sure that the replacement is working while replacing it. The code replacing functions, might use those function you are replacing.

Still, implementations allow you to replace CL functions - but this is implementation specific. For example LispWorks provides the variables lispworks:*packages-for-warn-on-redefinition* and lispworks:*handle-warn-on-redefinition*. One can bind them or change them globally.

What's the considered wisdom and best practice here please?

There are two approaches:

  • use implementation specific ways to replace standard Common Lisp functions

This can be dangerous. Plus you need to support it for all implementations of CL you want to use...

  • use a language package, where you define your new language. Here this would be standard Common Lisp plus your extensions/changes. Export everything the user would use. In your software use this package instead of CL.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 将 R S3 普通函数转换为泛型(Turning an R S3 ordinary function into a generic)
    问题 仅供参考,看起来这个问题已经有一个 LISP 等价物。 最近我想为 R 基本函数setdiff创建一个数据帧扩展,并认为泛型会很好。 以下工作但很笨重: #' @export setdiff.default setdiff.default <- setdiff #' @export setdiff <- function(x, ...) { UseMethod("setdiff") } #' @export setdiff.data.frame <- function(A, B) { A[!duplicated(rbind(B, A))[nrow(B) + 1:nrow(A)], ] } 加载包时,基本函数被屏蔽。 如果我为新函数编写额外的文档,则会创建另一个 .Rd 文件并与原始基本 R 函数竞争(R 要求您在运行?setdiff时选择您想要的?setdiff )。 有没有干净的方法来做到这一点? 回答1 可以使用 S4 来完成。 请注意, setdiff使用 x 和 y 作为参数,因此该方法也应该: setGeneric("setdiff") setdiff.data.frame <- function(x, y) { x[!duplicated(rbind(y, x))[nrow(y) + 1:nrow(x)], ] } setMethod("setdiff"
  • Turning an R S3 ordinary function into a generic
    FYI, looks like this question already has a LISP equivalent. Recently I wanted to create a dataframe extension to the R base function setdiff and thought a generic would be nice. The following works but is clunky: #' @export setdiff.default setdiff.default <- setdiff #' @export setdiff <- function(x, ...) { UseMethod("setdiff") } #' @export setdiff.data.frame <- function(A, B) { A[!duplicated(rbind(B, A))[nrow(B) + 1:nrow(A)], ] } When you load the package, the base function is masked. If I write extra documentation for the new function, an other .Rd file is created and competes with the
  • Haskell quasiquotation 如何用于替换 Haskell 级别的令牌?(How can Haskell quasiquotation be used for replacing tokens on the Haskell level?)
    问题 haskellwiki 中描述的准引用主要显示为将其他语言嵌入到 Haskell 中的有用工具,而不会弄乱字符串引用。 问题是:对于 Haskell 本身来说,为了替换标记并将结果传递给 ghc 的目的,将现有的 Haskell 代码放入一个 quasiquoter 有多容易? 也许模板 Haskell 是这里的关键? 我已经寻找了代码示例,但没有找到。 一些 EDSL 可以通过减小其组合运算符的大小(例如,将 'a .|. b .>>. c' 转为 '[myedsl|a | b >> c]')而受益于这种能力。 回答1 例如,您可以使用 haskell-src-meta 包构建操作 Haskell 代码的准引用器。 它将有效的 Haskell 代码解析为 AST,然后您可以对其进行修改。 在这种情况下,修改 AST 的最简单方法是使用 Data.Generics 将通用转换应用于整个 AST,用其他运算符替换运算符。 我们将从构建通用 Haskell 表达式的转换函数开始。 表示表达式的数据类型是 template-haskell 包中的 Exp。 例如,将运算符>>转换为.>>. 我们会使用像这样的函数 import Language.Haskell.TH (Exp(..), mkName) replaceOp :: Exp -> Exp replaceOp (VarE
  • Replacing templated function pointer by generic type
    I have written the following wrapper for std::bind and std::queue: #include "Queue.h" template<class T> Queue<T>::Queue(T* input) { instance = input; } template<class T> template<typename... Args> int Queue<T>::push(int (T::*func)(Args... args), Args... args) { queue.push(std::bind(func, instance, args...)); return queue.size(); } template<class T> int Queue<T>::pop() { if(!queue.empty()) { queue.front()(); queue.pop(); return queue.size(); } return 0; } template<class T> bool Queue<T>::empty() { return queue.empty(); } template<class T> size_t Queue<T>::size() { return queue.size(); } with
  • 什么是泛型编程与模板
    泛型编程 泛型编程简单来说就是编写与类型无关的通用代码,是代码复用的一种手段。而模板是泛型编程的基础。 举个简单的例子,假设我们需要写一个swap的交换函数,如果我们按部就班的正常去写的,那么针对以下情况我们就编写出好几种函数,仅仅为了一个简单的交换。 void swap(int& a, int& b);//针对int类型 void swap(double& a, double& b);//针对double类型 void swap(char& a, char& b);//针对char类型 但是,上述函数内部的操作却是相似的,于是为了解决这种问题,我们提出了泛型编程,我们用一个模具来代替类型,让编译器去识别,去替我们做那些重复的事情。 而我们的模具分为了函数模板和类模板,下面就对这两者进行逐一的介绍。 函数模板 概念 函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生特定的函数。也就是使用的时候让编译器来决定本次的类型到底是什么。 格式 template<typename T1, typename T2,......,typename Tn> 返回值类型 函数名(参数列表){} //以swap函数为例 template<typename T> void Swap( T& left, T& right) { T temp = left; left =
  • 通过将新类型指定为泛型的实际类型来扩展泛型有什么好处(What is the benefit of extending a generic by specifying the new type as actual type of generic)
    问题 我在某处看到了这种模式: class A extends B<A> { } 通过将新类型指定为泛型的实际类型来扩展泛型,这种结构有点不寻常。 有什么用? 这个图案有名字吗? 有没有替代模式? 示例:https://code.google.com/p/selenium/wiki/LoadableComponent 跳转到: public class EditIssue extends LoadableComponent<EditIssue> { 编辑:阅读回复后,我似乎需要改变我对编译器类型检查的理解。 在我的脑海里,我对这种模式的看法是,如果两个 A 需要相同,那么有没有办法不重复它们? 但似乎没有更好的方法将派生类的类型传播到父类。 回答1 当然,OOP 的答案是A是B 。 如果A不是B ,则A应该仅将自己与B以利用B的功能。 大概B也有一些通用实现,它们利用了对泛型类型的限制。 另一个用例是B看起来像: abstract class B<T extends B<T>> { public T createCopy(T t); } 现在子类可以实现createCopy并且客户端代码可以安全地使用它而无需强制转换......例如 class A extends B<A> { public A createCopy(A t) { return new A(t); //copy
  • 用泛型类型替换模板化函数指针(Replacing templated function pointer by generic type)
    问题 我为std::bind和std::queue编写了以下包装器: #include "Queue.h" template<class T> Queue<T>::Queue(T* input) { instance = input; } template<class T> template<typename... Args> int Queue<T>::push(int (T::*func)(Args... args), Args... args) { queue.push(std::bind(func, instance, args...)); return queue.size(); } template<class T> int Queue<T>::pop() { if(!queue.empty()) { queue.front()(); queue.pop(); return queue.size(); } return 0; } template<class T> bool Queue<T>::empty() { return queue.empty(); } template<class T> size_t Queue<T>::size() { return queue.size(); } 带有以下标题: #ifndef QUEUE_H_ #define QUEUE
  • 什么是C ++上下文的单态化?(What is monomorphisation with context to C++?)
    问题 戴夫·赫尔曼(Dave Herman)最近在Rust的演讲中说,他们从C ++借用了此属性。 我找不到关于该主题的任何内容。 有人可以解释一下单质化的含义吗? 回答1 单一化意味着生成通用功能的专用版本。 如果我编写了一个提取任何一对第一个元素的函数: fn first<A, B>(pair: (A, B)) -> A { let (a, b) = pair; return a; } 然后我两次调用此函数: first((1, 2)); first(("a", "b")); 编译器将生成first()两个版本, first()版本专用于整数对,另一个版本专用于字符串对。 该名称源自编程语言术语“多态性”,即一种可以处理多种类型数据的功能。 单态化是从多态代码到单态代码的转换。 回答2 不确定是否有人还在看这个,但是Rust文档实际上确实提到了它如何通过此过程实现了成本抽象。 从使用泛型的代码性能来看: 您可能想知道使用泛型类型参数时是否会产生运行时成本。 好消息是,Rust以这样的方式实现泛型,即使用泛型类型的代码不会比使用具体类型的代码运行慢。 Rust通过在编译时对使用泛型的代码进行单态化来实现这一点。 单色化是通过填充编译时使用的具体类型,将通用代码转换为特定代码的过程。 在此过程中,编译器执行与清单10-5中用于创建泛型函数的步骤相反的操作
  • C++提高编程(一)—— 模板(上)
    C++系列内容的学习目录 → \rightarrow →C++学习系列内容汇总。1. 模板的概念2. 函数模板2.1 函数模板语法2.2 函数模板注意事项2.3 函数模板案例2.4 普通函数与函数模板的区别2.5 普通函数与函数模板的调用规则2.6 模板的局限性3. 类模板  模板分为两个篇章。     1、2部分的内容见C++提高编程(一)—— 模板(上)     3部分的内容见C++提高编程(一)—— 模板(下)1. 模板的概念  模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。  模板是创建泛型类或函数的蓝图或公式。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。每个容器都有一个单一的定义,比如向量,我们可以定义许多不同类型的向量,比如 vector 或 vector 。  模板就是建立通用的模具,大大提高复用性,我们可以使用模板来定义函数和类。  模板的特点:1. 模板不可以直接使用,它只是一个框架;         2. 模板的通用并不是万能的。2. 函数模板C++另一种编程思想称为泛型编程 ,主要利用的技术就是模板;C++提供两种模板机制:函数模板和类模板 。2.1 函数模板语法  函数模板的作用:建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。  函数模板的语法:template
  • 用零替换模型(ODE 系统)中的负值(Replacing negative values in a model (system of ODEs) with zero)
    问题 我目前正在使用deSolve解决常微分方程组,并且想知道是否有任何方法可以防止微分变量值低于零。 我看过其他一些关于将向量、数据框等中的负值设置为零的帖子,但由于这是一个生物模型(并且 T 细胞计数变为负值没有意义),我需要从一开始就阻止它发生,因此这些值不会扭曲结果,而不仅仅是替换最终输出中的负数。 回答1 我的标准方法是将状态变量转换为不受约束的比例。 对正变量执行此操作的最明显/标准方法是写下log(x)而不是x的动力学方程。 例如,对于传染病流行的易感感染恢复 (SIR) 模型,其中方程为dS/dt = -beta*S*I; dI/dt = beta*S*I-gamma*I; dR/dt = gamma*I dS/dt = -beta*S*I; dI/dt = beta*S*I-gamma*I; dR/dt = gamma*I dS/dt = -beta*S*I; dI/dt = beta*S*I-gamma*I; dR/dt = gamma*I我们会天真地将梯度函数写为 gfun <- function(time, y, params) { g <- with(as.list(c(y,params)), c(-beta*S*I, beta*S*I-gamma*I, gamma*I) ) return(list(g)) } 如果我们让 log(I) 而不是 I
  • C++泛型编程:函数对象(仿函数)和谓词的概念、常见内建函数对象
    要学习标准库STL,就不得不去了解函数对象和谓词,于是本人今天写篇博客做简要总结。 函数对象 概念:重载函数调用操作符的类,其对象称为函数对象。函数对象使用重载的()时,行为类似函数调用,因此也称为仿函数。另外,仿函数并不是类的特权,在结构体中也可以通过重载()实现仿函数。 本质:是一个类,或是一个结构体,不是一个函数。 使用特点: 1.函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值。例如: #include<iostream> using namespace std; class myAdd { public: int operator()(int a, int b) { return a + b; } }; int main() { myAdd add; cout << myAdd()(1, 2) << endl;//通过创建匿名函数对象调用() cout << add(3, 4) << endl;//通过函数对象调用() return 0; } 2.函数对象超出普通函数的概念,函数对象可以有自己的状态。因为函数对象本质是一个类,所以可以在类内创建记录函数状态的成员,而普通函数无法做到,比如想要知道普通函数的调用次数,需要用户自己定义变量计数。例如: #include<iostream> #include<string> using namespace
  • Go泛型提案已提交,Go 1.18 beta有望试用
    喜欢就关注我们吧! Go 团队核心成员 Ian Lance Taylor 宣布已提交为 Go 添加泛型的提案 (Proposal)。 Ian 在博客说道:“为 Go 添加泛型的语言变更完全向后兼容 (fully backward compatible),现有的 Go 程序会继续像现在一样正常运行。” Ian 还表示如果提案能通过,Go 团队会在年底前发布一个完整但可能未优化的实现,以供开发者试用,或许会在 Go 1.18 beta 中提供。 泛型草案设计概要•函数可以使用带方括号的类型参数列表,类型参数列表的其他方面和普通参数列表一样: func F[T any](p T) { ... } •这些类型参数可以被常规参数使用,也可以在函数体中使用 •类型 (Types) 也可以使用类型参数列表: type M[T any] []T •每个类型参数都有一个类型约束,正如普通参数都有一个类型:func F[T Constraint](p T) { ... } •类型约束属于接口类型 •新的预声明名称any是允许任何类型的类型约束 •用作类型约束的接口类型可以使用预声明类型的列表;只有与这些类型之一相匹配的类型参数才能满足约束条件 •泛型函数只能使用其类型约束所允许的操作 •使用泛型函数或类型需要传递类型参数 •在通常情况下,类型推断允许省略函数调用的类型参数 详情查看:Proposal
  • java面向对象学习心得体会
    java面向对象学习心得体会 文章目录 java面向对象学习心得体会类与对象封装性this用法普通方法调用(不强行要求添加this)构造方法重载this调用优化简单java类开发一般原则:static关键字代码块数组string类型继承性覆写object类包装类泛型包的定义与使用枚举类型异常处理内部类 类与对象 java中所有属性和方法都在类中,一个程序可以包含一个主类,和若干类 主类public class的名称只能与文件名相同。 java的类中包括属性和方法,一般由主类进行对象实例化,new一个对象的时候,系统统一开辟了一个堆内存存放属性数据,栈内存存放其堆内存的地址。给属性赋值就是与对象建立联系。 封装性 java中常使用private对类中属性进行封装,使用getting和setting方法用于调用 set用于设置get用于返回给属性 this用法 构造方法此时没有访问类和属性的区别,往往属性前追加一个this public person(string name,int age) { this.name=name; this.age=age; } 访问本类中属性时,属性前加this. this调用本类方法(构造与普通方法) 普通方法调用(不强行要求添加this) 构造方法重载this调用优化 this()语句仅允许放在构造方法首行 构造方法互相调用保留程序出口不形成死循环
  • 替换一个数据块中的多个模式(Replacing multiple patterns in a block of data)
    问题 我需要找到在单个文本块上匹配多个正则表达式的最有效方法。 举一个我需要的例子,考虑一个文本块: “你好世界,多么美好的一天” 我想用“再见”代替“Hello”,用“宇宙”代替“世界”。 我总是可以在循环中做到这一点,使用各种语言中可用的 String.replace 函数之类的东西。 但是,我可能有一大块带有多个字符串模式的文本,我需要匹配和替换。 我想知道我是否可以使用正则表达式来有效地做到这一点,或者我是否必须使用像 LALR 这样的解析器。 我需要在 JavaScript 中做到这一点,所以如果有人知道可以完成它的工具,我们将不胜感激。 回答1 您可以传递一个函数来替换: var hello = "Hello World what a beautiful day"; hello.replace(/Hello|World/g, function ($0, $1, $2) // $3, $4... $n for captures { if ($0 == "Hello") return "Bye"; else if ($0 == "World") return "Universe"; }); // Output: "Bye Universe what a beautiful day"; 回答2 编辑 在我最初的答案(如下)6 年后,我会以不同的方式解决这个问题
  • Can't fix warning when redefining log as a generic
    I would like to make the log function a generic so that I can alter it's behavior under some newclass. I have a minimal package with a DESCRIPTION file: Package: logmethod Type: Package Title: A new Log Method Version: 0.1 Date: 2017-03-23 Author: Me Maintainer: Who to complain to <yourfault@somewhere.net> Description: More about what it does (maybe more than one line) License: MIT LazyData: TRUE RoxygenNote: 5.0.1 And the R Code, based on what I've learned at Writing R Extensions and Is it bad style to redefine non-S3 base functions as S3 functions in an R package? #' @name log_method #'
  • 如何在clojure中设置和获取多方法元数据?(How to set and get multimethod metadata in clojure?)
    问题 我正在使用多方法来解析命令行命令及其参数。 (defmulti run (fn [command args] command)) (defmethod run :default [& _] ...) ^{:args "[command]"} (defmethod run "help" [_ & [args]] "Display command list or help for a given command" ...) ^{:args ""} (defmethod run "version" [_ & [args]] "Print program's version" ...) (defn -main [& args] (run (first args) (next args))) 当我尝试访问元数据时,对于特定方法,clojure 返回nil : (meta ((methods run) "help")) 回答1 没有这种可能。 第一个原因(直截了当)是defmethod不提供为特定方法设置元数据的能力(只有defmulti允许,但仅限于整个多方法)。 第二个原因是 multimethod 本质上是一个单一的函数,只是有多个执行“变体”,每个“变体”都根据传递的参数触发。 粗略地说,从调用者的角度来看,下面定义的函数f1和f2之间没有特别的区别: (defmulti f1
  • 用一个反斜杠替换空白(Replacing white space with one single backslash)
    问题 我想用一个反斜杠和一个像这样的空格替换一个空格: "foo bar" --> "foo\ bar" 我找到了如何用多个反斜杠替换,但无法将其调整为单个反斜杠。 到目前为止我试过这个: x <- "foo bar" gsub(" ", "\\ ", x) # [1] "foo bar" gsub(" ", "\\\ ", x) # [1] "foo bar" gsub(" ", "\\\\ ", x) # [1] "foo\\ bar" 然而,所有的结果都不能满足我的需求。 我需要替换以动态创建包含名称如下的文件夹的文件路径 /some/path/foo bar/foobar.txt 。 要将它们用于system()空格中的 shell 命令,必须使用\退出 /some/path/foo\ bar/foobar.txt 。 你知道如何解决这个问题吗? 回答1 您的问题是字符串的内容与其表示形式之间的混淆。 当你在 R 中以普通方式打印出一个字符串时,你永远不会看到一个反斜杠(除非它表示一个特殊字符,例如print("y\n") 。如果你使用cat()代替,你只会看到一个反斜杠。 x <- "foo bar" y <- gsub(" ", "\\\\ ", x) print(y) ## [1] "foo\\ bar" cat(y,"\n") ## string followed
  • 如何有效地小写集合的每个元素?(How to lowercase every element of a collection efficiently?)
    问题 小写List或Set的每个元素的最有效方法是什么? 我对清单的想法: final List<String> strings = new ArrayList<String>(); strings.add("HELLO"); strings.add("WORLD"); for(int i=0,l=strings.size();i<l;++i) { strings.add(strings.remove(0).toLowerCase()); } 有没有更好,更快的方法? 对于Set,此示例的外观如何? 由于当前没有方法可以将操作应用于集合(或列表)的每个元素,而无需创建其他临时集合? 这样的事情会很好: Set<String> strings = new HashSet<String>(); strings.apply( function (element) { this.replace(element, element.toLowerCase();) } ); 谢谢, 回答1 对于列表,这似乎是一个非常干净的解决方案。 它应该允许使用特定的List实现来提供对于在线性时间内遍历列表以及在恒定时间内替换字符串都是最佳的实现。 public static void replace(List<String> strings) { ListIterator<String> iterator
  • 如何求解具有时变参数的常微分方程组(How solve a system of ordinary differntial equation with time-dependent parameters)
    问题 如何解决参数取决于时间或自变量的常微分方程系统..初值问题...。 说我有等式 Dy(1)/dt=a(t)*y(1)+b(t)*y(2); Dy(2)/dt=-a(t)*y(3)+b(t)*y(1); Dy(3)/dt=a(t)*y(2); 其中a(t)是一个向量,b(t)= c * a(t); 其中a和b的值随时间变化,而不是以单调的方式而不是每个时间步长变化。 我试图用这篇文章解决这个问题....但是当我应用相同的原理时...我收到了错误消息 “使用griddedInterpolant时出错。点坐标未按严格的单调顺序排序。” 有人可以帮我吗? 回答1 请仔细阅读直到结尾,看看答案的第一部分还是第二部分与您相关: 第1部分:首先创建一个.m文件,该文件具有一个描述您的计算的函数以及将给出a和b函数。 例如:创建一个名为fun_name.m的文件,其中将包含以下代码: function Dy = fun_name(t,y) Dy=[ a(t)*y(1)+b(t)*y(2); ... -a(t)*y(3)+b(t)*y(1); ... a(t)*y(2)] ; end function fa=a(t); fa=cos(t); % or place whatever you want to place for a(t).. end function fb=b(t); fb=sin
  • 16. C++泛型编程(函数模板)
    C++中如何交换两个变量的值? 你注意到了么?除了类型不同,函数体代码完全相同!!! C++强调代码复用!那如何解决这个代码冗余的问题呢? 泛型编程 泛型编程的概念:不考虑具体数据类型的编程模式。 C++中,泛型编程是通过函数模板。1. 函数模板是一种特殊的函数可用不同类型进行调用;2. 函数模板看起来和普通函数很相似,区别是类型可被参数化; 函数模板的语法规则 template关键字用于声明开始进行泛型编程 typename关键字用于声明泛指类型 函数模板的应用 1. 自动类型推导调用 2. 具体类型显示调用 #include <cstdlib> #include <iostream> using namespace std; template<typename T> void Swap(T& a, T& b) { T t = a; a = b; b = t; } int main(int argc, char *argv[]) { int a = 1; int b = 2; Swap(a, b); cout<<"a = "<<a<<endl; cout<<"b = "<<b<<endl; float fa = 3; float fb = 4; Swap<float>(fa, fb); cout<<"fa = "<<fa<<endl; cout<<"fb = "<<fb<