模板类型应该紧随其后
一个“概念”(输入迭代器,前进
迭代器,等等…
定义了概念的细节
完全由实现的
模板函数/类,而不是由
类所使用的类型的类
模板,这是一个
反对使用面向对象编程。
我认为您误解了模板对概念的预期用途。例如,前向迭代器是一个定义非常明确的概念。要找到使类成为前向迭代器必须有效的表达式,以及它们的语义(包括计算复杂性),可以查看标准或http://www.sgi.com/tech/stl/ForwardIterator.html(必须按照Input、Output和Trivial Iterator的链接查看所有内容)。
该文档是一个非常好的界面,“概念的实际细节”就定义在那里。它们不是由前向迭代器的实现定义的,也不是由使用前向迭代器的算法定义的。
STL和Java处理接口的方式有三个不同之处:
1) STL使用对象定义了有效的表达式,而Java定义了必须在对象上调用的方法。当然,有效表达式可能是一个方法(成员函数)调用,但这并不一定是必须的。
2) Java接口是运行时对象,而STL概念在运行时是不可见的,即使使用RTTI。
3)如果你不能使STL概念所需的有效表达式有效,当你实例化一些模板时,你会得到一个未指定的编译错误。如果您未能实现Java接口的必要方法,则会得到一个特定的编译错误。
第三部分是如果你喜欢某种(编译时)"duck typing":接口可以是隐式的。在Java中,接口是显式的:当且仅当一个类说它实现了Iterable时,它才是Iterable。编译器可以检查它的方法的签名是否都存在并且正确,但是语义仍然是隐式的(即它们要么被记录下来,要么没有,但只有更多的代码(单元测试)才能告诉你实现是否正确)。
In C++, like in Python, both semantics and syntax are implicit, although in C++ (and in Python if you get the strong-typing preprocessor) you do get some help from the compiler. If a programmer requires Java-like explicit declaration of interfaces by the implementing class, then the standard approach is to use type traits (and multiple inheritance can prevent this being too verbose). What's lacking, compared with Java, is a single template which I can instantiate with my type, and which will compile if and only if all the required expressions are valid for my type. This would tell me whether I've implemented all the required bits, "before I use it". That's a convenience, but it's not the core of OOP (and it still doesn't test semantics, and code to test semantics would naturally also test the validity of the expressions in question).
STL对你来说可能是OO,也可能不是,但它确实把接口和实现清晰地分开了。它确实缺乏Java在接口上进行反射的能力,并且它以不同的方式报告违反接口需求的情况。
你可以告诉函数。期望前向迭代器仅为
看它的定义,你需要看
实现或文档…
Personally I think that implicit types are a strength, when used appropriately. The algorithm says what it does with its template parameters, and the implementer makes sure those things work: it's exactly the common denominator of what "interfaces" should do. Furthermore with STL, you're unlikely to be using, say, std::copy based on finding its forward declaration in a header file. Programmers should be working out what a function takes based on its documentation, not just on the function signature. This is true in C++, Python, or Java. There are limitations on what can be achieved with typing in any language, and trying to use typing to do something it doesn't do (check semantics) would be an error.
That said, STL algorithms usually name their template parameters in a way which makes it clear what concept is required. However this is to provide useful extra information in the first line of the documentation, not to make forward declarations more informative. There are more things you need to know than can be encapsulated in the types of the parameters, so you have to read the docs. (For example in algorithms which take an input range and an output iterator, chances are the output iterator needs enough "space" for a certain number of outputs based on the size of the input range and maybe the values therein. Try strongly typing that.)
以下是Bjarne对显式声明接口的介绍:http://www.artima.com/cppsource/cpp0xP.html
In generics, an argument must be of a
class derived from an interface (the
C++ equivalent to interface is
abstract class) specified in the
definition of the generic. That means
that all generic argument types must
fit into a hierarchy. That imposes
unnecessary constraints on designs
requires unreasonable foresight on the
part of developers. For example, if
you write a generic and I define a
class, people can't use my class as an
argument to your generic unless I knew
about the interface you specified and
had derived my class from it. That's
rigid.
从另一个角度来看,使用duck类型,您可以在不知道接口存在的情况下实现接口。或者有人可以故意编写一个接口,让你的类实现它,并咨询你的文档,看看他们不会要求任何你没有做过的事情。这是灵活的。