- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在this question中,OP询问了如何限制模板接受的类。随之而来的观点总结是,Java中的等效功能很糟糕;不要这样做
我不明白为什么这很糟糕。鸭子打字无疑是一个强大的工具。但是在我看来,当类看起来很接近(函数名称相同)但行为略有不同时,它会给自己带来困惑的运行时问题。由于以下示例,您不一定要依赖编译时检查:
struct One { int a; int b };
struct Two { int a; };
template <class T>
class Worker{
T data;
void print() { cout << data.a << endl; }
template <class X>
void usually_important () { int a = data.a; int b = data.b; }
}
int main() {
Worker<Two> w;
w.print();
}
Two
仅在未调用
Worker
的情况下才允许
usually_important
进行编译。这可能会导致
Worker
编译的某些实例化,甚至导致不在同一程序中的实例化。
ENGINE
的设计者承担,以确保它是有效的类型(在此之后,他们应该继承
ENGINE_BASE
)。如果不这样做,将出现编译器错误。对我来说,这似乎更安全,同时不施加任何限制或增加很多其他工作。
class ENGINE_BASE {}; // Empty class, all engines should extend this
template <class ENGINE>
class NeedsAnEngine {
BOOST_STATIC_ASSERT((is_base_of<ENGINE_BASE, ENGINE>));
// Do stuff with ENGINE...
};
最佳答案
这太长了,但可能会提供引用。
Java中的泛型是一种类型擦除机制,可以自动生成类型转换和类型检查的代码。
C++中的template
是代码生成和模式匹配机制。
您可以使用C++的template
来完成Java泛型的工作。 std::function< A(B) >
在A
和B
类型以及转换为其他std::function< X(Y) >
方面表现出协变/相反的方式。
但是两者的主要设计并不相同。
Java List<X>
将是上面带有一些薄包装的List<Object>
,因此用户不必在提取时进行类型转换。如果将其作为List<? extends Bar>
传递,则本质上又会获得List<Object>
,它仅具有一些额外的类型信息,这些信息会更改强制转换的工作方式以及可以调用的方法。这意味着您可以将List
中的元素提取到Bar
中并知道它可以工作(并检查)。所有List<? extends Bar>
仅生成一种方法。
C++ std::vector<X>
本质上不是std::vector<Object>
或std::vector<void*>
或其他任何东西。 C++ template
的每个实例都是不相关的类型(模板模式匹配除外)。实际上,std::vector<bool>
使用的实现与其他任何std::vector
完全不同(现在被认为是错误的,因为在这种情况下,实现会以令人讨厌的方式“泄漏”)。每个方法和函数都是针对您传递给它的特定类型而独立生成的。
在Java中,假定所有对象都适合某个层次结构。在C++中,这有时很有用,但是已经发现它通常不适合解决问题。
C++容器不需要从公共(public)接口(interface)继承。 std::list<int>
和std::vector<int>
是不相关的类型,但是您可以对它们进行统一操作-它们都是顺序容器。
问题“参数是否为顺序容器”是一个好问题。这使任何人都可以实现顺序容器,并且这种顺序容器可以与完全不同的实现方式像手工制作的C代码一样具有高性能。
如果您创建了一个公共(public)根std::container<T>
,所有容器都从该根目录继承而来,那么它要么充满virtual
表屑,要么除了用作标记类型外,它将无用。作为标记类型,它将以侵入方式将其自身注入(inject)所有非std
容器,要求它们从std::container<T>
继承为真实容器。
相反,特征方法意味着有关于容器(顺序容器,关联容器等)的规范。您可以在编译时测试这些规范,和/或允许类型通过某种特征来说明它们符合某些公理的条件。
C++ 03/11标准库使用迭代器执行此操作。 std::iterator_traits<T>
是一个traits类,它公开有关任意类型T
的迭代器信息。完全不连接标准库的人可以编写自己的迭代器,并使用std::iterator<...>
自动处理std::iterator_traits
,手动添加自己的类型别名或专门设置std::iterator_traits
来传递所需的信息。
C++ 11更进一步。 for( auto&& x : y )
可以处理在设计基于范围的迭代之前就编写的东西,而无需接触类本身。您只需在该类所属的 namespace 中编写一个免费的begin
和end
函数,该函数会返回有效的正向迭代器(注意:即使是足够接近工作的无效正向迭代器),然后for ( auto&& x : y )
也会突然开始工作。std::function< A(B) >
是将这些技术与类型擦除结合使用的示例。它具有一个构造函数,该构造函数可以接受可以使用(B)
复制,销毁和调用的任何内容,并且其返回类型可以转换为A
。它可以采用的类型可以完全不相关-仅测试所需的类型。
由于std::function
的设计,我们可以有不相关类型的lambda可调用项,可以在需要时将其类型擦除为通用的std::function
,但是如果不进行类型擦除,则可以从那里知道它们的调用 Action 。因此,采用lambda的template
函数在调用时就知道会发生什么,这使内联变得容易。
这项技术不是什么新技术,它是C++中的一种语言,因为std::sort
是一种高级算法,由于易于内联作为比较器传递的可调用对象,因此它比C的qsort
更快。
简而言之,如果您需要通用的运行时类型,请键入“擦除”。如果需要某些属性,请测试这些属性,不要强加共同基础。如果需要某些公理来保存(不可修改的属性),请记录文档或要求调用者通过标签或特征类声明这些属性(请参阅标准库如何处理迭代器类别-再次,而不是继承)。如有疑问,请使用启用了ADL的自由函数来访问参数的属性,并让您的默认自由函数使用SFINAE查找方法并调用(如果存在),否则将失败。
这种机制消除了常见基类的主要责任,允许对现有类进行修改而无需修改以通过您的要求(如果合理),仅将类型擦除放置在需要的地方,避免virtual
开销,并且理想情况下在属性时生成清晰的错误被发现不成立。
如果您的ENGINE
有某些特性需要通过,请编写一个测试这些特性的traits类。
如果存在无法测试的属性,请创建描述此类属性的标签。使用traits类或规范的typedef的特殊化,让该类描述针对该类型的公理。 (请参见迭代器标签)。
如果您有类似ENGINE_BASE
的类型,请不要使用它,而应将其用作上述标记和特征以及std::iterator<...>
这样的公理typedef的帮助器(您不必继承它,它只是充当帮助器)。
避免过度指定要求。如果usually_important
从未在Worker<X>
上调用,则在这种情况下,您的X
可能不需要b
。但是,以比“方法无法编译”更清晰的方式测试属性。
有时,只是平底锅。遵循这样的做法可能会使您的工作变得更困难-因此,请采用一种更简单的方法。大多数代码被编写并丢弃。知道您的代码何时可以持久保存,并更好,更可扩展,更可维护地编写代码。知道您需要在一次性代码上练习这些技术,以便在需要时可以正确地编写它们。
关于c++ - 为什么在C++中对模板施加类型约束很不好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25386765/
非常简单的应用程序 - 您可以复制 - 粘贴 - 运行。主要只是“创建”应用程序。 - 这不是问题(可能) #include #include #include #include typede
关闭。这个问题需要details or clarity .它目前不接受答案。 想改进这个问题吗? 通过 editing this post 添加细节并澄清问题. 关闭 6 年前。 Improve t
Haskell 有一个名为 seq 的神奇函数,它接受任何类型的参数并将其简化为弱头范式 (WHNF)。 我读过一些资料[但我现在不记得他们是谁了...],它们声称“多态 seq 很糟糕”。他们在哪些
我正在编写一个脚本,该脚本应该在一堆服务器周围运行并从中选择一堆数据,包括本地服务器。选择我需要的数据所需的 SQL 非常复杂,所以我正在编写一种临时 View ,并使用 OPENQUERY 语句来获
考虑以下代码: case class Vector3(var x: Float, var y: Float, var z: Float) { def add(v: Vector3): Unit =
我正在读这个SO post关于守护线程,答案底部的引述是: But joining a demonized thread opens most likely a whole can of troubl
在阅读有关 Google webtool 工具包的内容时,看到一条声明说“同步 RPC 不好”。他们有什么理由吗?我能想到的一个很好的理由是,对最终用户的响应可能会受到远程服务器延迟或网络问题的影
我有以下 HTML: A Simple Sample Web Page By Sheldon Brown Demonstrating a few HTML feat
我正在做一项简单的任务,但我陷入困境...... output 我需要使第一行与其他所有内容保持一致,但无论我做什么,它都不想接受空格。那么,我应该纠正什么以及为什么?谢谢 public static
我在系统中有一个类,其目的列为“这可以是从午夜算起的秒数。或者带有日期的时间。”我试图解释这有多糟糕,但我无法理解我的观点。有没有人对如何解决这个问题有任何想法。 http://code-slim-j
这个问题在这里已经有了答案: 关闭 11 年前。 Possible Duplicate: When are C++ macros beneficial? Why is #define bad and
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 8 年前。 Improve
始终建议通过将所有代码放在 JS 文件中来避免内联 Javascript 代码,该文件包含在所有页面中。我想知道,这是否不会导致繁重的页面出现性能问题。 例如,假设我们有几十个这样的函数 functi
我主要在 AngularJS 中进行开发,最近我正在研究 Vue.js 并阅读它的指南,在它提到的一页上: By default, all props form a one-way-down bind
我正在构建一个本地化目录,但遇到了设计难题。现在,目录存储一个 Dictionary存储翻译,其中 IString可以是两种类型:Singular或 Plural .这是 IString 的简化版本:
对于我的矩阵类,我做了: template class Matrix { private: std::array, Height> Elements; stat
MSDN documentation说 public class SomeObject { public void SomeOperation() { lock(this) {
建议不要在 Python 中使用 import *。 谁能分享一下原因,这样我下次就可以避免了? 最佳答案 因为它会将很多东西放入您的命名空间(可能会影响之前导入的一些其他对象,而您不会知道它)。 因
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 7年前关闭。 Improve thi
G'day, 这与my question on star developers有关并到 this question regarding telling someone that they're wri
我是一名优秀的程序员,十分优秀!