问题标签 [crtp]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
2 回答
1442 浏览

c++ - c++派生类的类型列表

使用 CRTP(奇怪的重复模板模式),您可以为基类提供派生类的知识。创建一个数组来存储从基类派生的每个类的实例并不难(参见示例)

我想知道是否可以创建所有派生类类型的 Typelist(请参阅http://www.research.ibm.com/designpatterns/pubs/ph-jun00.pdf)。问题是,每次编译器看到一个派生自Base它的新类时,都需要将新类型附加到列表中,但类型列表是不可变的(可以创建一个附加新类型的新列表,但添加据我所知,列表中的元素是不可能的。最后我想要这样的东西:

最终目标是能够遍历所有派生自Base.

0 投票
2 回答
1323 浏览

c++ - C++:CRTP 析构函数?

在一个项目中,我有以下问题:

我有一个非常简单的继承方案(我需要继承而不是组合):

类基础

-> 类 DerivedA

-> 类 DerivedB

-> 类 DerivedC

A、B 和 C 从 Base 派生,仅此而已。所以现在我有两个选择:

具有虚拟性的公共继承

没有虚拟性的私有继承

由于某些优化原因(我需要大量内联),我不想要虚拟性......而且我不想要私有继承。我认为剩下的唯一选择是 CRTP。但是基类有大约 300 个函数,在其中实现 CRTP 将是一个真正的痛苦。

所以我想知道以下解决方案是否有效:我只在基类的析构函数中使用 CRTP:

其中 TCRTP 将是 DerivedA、B 或 C,我进行公共继承。完全没问题,还是有问题?

非常感谢你。

0 投票
2 回答
3443 浏览

c# - 如何在 C# 中编写一个好的奇怪重复模板模式 (CRTP)

不久前,我想创建自己的数据映射器,它比普通的 ORM 简单得多。在这样做的过程中,我发现需要访问我的基类中继承类的类型信息。我的第一个想法是反射,但它太慢了(如果你使用反射,请查看Fasterflect,因为它“几乎”消除了反射的性能问题)。

所以我转向了一个解决方案,后来我发现它有自己的名字:The Curiously Recurring Template Pattern。这主要解决了我的问题,但是学习如何正确实现这种模式有点挑战。我必须解决的两个主要问题是:

1)如何让我的消费代码与我的通用对象一起工作,而无需知道创建对象的通用参数?

2) 如何在 C# 中继承静态字段?

具有挑战性的部分实际上是弄清楚问题。一旦我意识到我需要做什么,解决这些问题就很容易了。如果您发现自己需要 CRTP,您可能会发现自己需要回答这些问题……它们似乎齐头并进。

0 投票
2 回答
370 浏览

c++ - 带有 CRTP 的 C++ SFINAE,G++ 编译错误

我想知道以下代码是否有效。

最初的意图是,我喜欢一个基类,它将对某个成员的调用分派给派生类成员(如果存在),或者如果派生类没有该成员,则回退到默认行为。另一个用途是这个基类可以自己使用,Derived模板参数成为实现策略。clang++无论如何,下面的 MWE 可以在、Intelicpc和 MSVS上正确编译和运行。但是,它失败了g++(从 4.4 到 4.6,我使用过的任何版本),并在问题末尾显示错误消息。

如果我将call点 (1)、(2)、(3) 更改为call_dispatch(这是我最初所做的那种事情),g++就不会再抱怨了。我认为调度函数和调用者具有相同的名称不是一个好习惯。我只是好奇它是否会起作用,并且好奇地尝试一下(我不知道这个想法是如何产生的)。我这样做的理由是,在品脱 (1) 处,call使用一个参数调用,因此重载决议将不匹配其调用者,即零参数一。它也不会匹配SFINAE点 (2) 处的那个,因为D2没有成员,然后它应该匹配点 (3) 处的那个。就像 (1)-(3) 被命名的情况一样call_dispatch

g++不同意我和其他编译器。那么,是不正确的实现g++还是代码本身无效?除了错误信息真的很混乱。void (B<D2>::*)()和从何&B<D2>::call而来?Int 他调用的成员指针被定义为D2' 的成员。

错误:

编辑

虽然我还没有完全理解上面的代码出了什么问题。但我认为还有另一种方法,无需专门构建 SFINAE 类,但存档相同的效果。

基本上,因为D1D2都是从 派生的B,所以表达式&Derived::call总是会被解析。在D1它解析为&D1::call,然后使用模板版本成员。在D2中,它没有自己的,call因此&D2::call解决 了 所以使用默认调用。&B::call
&D2::callB::call

可以帮我看看这个新代码是否有任何缺陷?

0 投票
2 回答
982 浏览

c++ - 如何统计一个模板类的 CRTP 子类数量?

有谁知道使用 CRTP 计算对象子类数量的方法?

假设我们有一个类似于以下的设置:

等等,这样,使用 TMP,我们可能有一个常数 ( ObjectSubClassCount) 来表示子类的总数?

有谁知道这样做的方法?

编辑:我想稍后将结果用作模板参数,所以我需要使用 TMP 来完成...

0 投票
6 回答
2458 浏览

c++ - 防止用户从不正确的 CRTP 基础派生

我想不出一个合适的问题标题来描述这个问题。希望下面的详细信息可以清楚地解释我的问题。

考虑以下代码

尽管 的定义D2是故意错误的,但它会编译并运行。第一次调用将输出一些预期未初始化d2.call_impl()的随机位。D2::data_第二次和第三次调用都将输出100.data_

我明白为什么它会编译和运行,如果我错了,请纠正我。

当我们进行调用d2.call()时,调用被解析为Base<D1>::call,并且将this转换为D1和调用D1::call_impl。因为D1确实是派生形式Base<D1>,所以在编译时强制转换很好。

在运行时,在强制转换之后this,虽然它确实是一个D2对象,但它被视为好像它是D1,并且调用D1::call_impl将修改应该是的内存位D1::data_,并输出。在这种情况下,这些位恰好在哪里D2::data_。我认为第二个d2.call_impl()也应该是未定义的行为,具体取决于 C++ 实现。

关键是,这段代码虽然本质上是错误的,但不会给用户任何错误的迹象。我在我的项目中真正做的是我有一个 CRTP 基类,它就像一个调度引擎。库中的另一个类访问 CRTP 基类的接口,比如callcall并将调度到call_dispatch该接口,可以是基类默认实现或派生类实现。如果用户定义的派生类,比如说D,确实是从Base<D>. 如果它源自Base<Unrelated>whereUnrelated不是源自Base<Unrelated>. 但它不会阻止用户编写上述代码。

用户通过从基 CRTP 类派生并提供一些实现细节来使用该库。当然还有其他设计方案可以避免上述错误使用的问题(例如抽象基类)。但是让我们暂时把它们放在一边,相信我因为某种原因我需要这个设计。

所以我的问题是,有什么方法可以防止用户编写错误的派生类,如上所示。也就是说,如果用户编写了一个派生的实现类,比如D,但他是从 派生的Base<OtherD>,那么将引发编译时错误。

一种解决方案是使用dynamic_cast. 但是,这是广泛的,即使它有效,它也是一个运行时错误。

0 投票
1 回答
765 浏览

c++ - Boost.Parameter:命名模板参数与 CRTP 结合

警告:前面需要冗长的介绍来解释问题。在 Vandevoorde 和 Josuttis 的 ch 16.1 中首次描述的命名模板参数习语可以使用Boost.Parameter库方便地编写

上面的代码允许通过命名它们和覆盖BreadSlicer任意顺序的可选模板参数。这使得使用许多默认参数进行基于策略的设计非常方便。Policy1_isPolicy2_is

为了避免基于策略的设计非常微妙的 ODR 违规(有关解释,请参阅 Alexandrescu 的这篇旧帖子),我希望能够在命名模板参数上应用 CRTP 模式:

但是,上面的 Boost.Parameter 实现无法编译,因为一些内部 static_assert 失败并显示类似 (VC10 SP1) 的消息

'main::CuriousBreadSlicer' :不允许将未定义的类作为编译器内在类型特征 '__is_base_of' 的参数

问题:这个静态检查可以关闭吗?通过宏或模板技巧?

至于可能的解决方法:

  1. 上面的代码在功能上等同于这个手写代码。对于该代码,CRTP 模式确实有效。然而,它需要大量的样板代码,Boost.Parameter 库可以方便地自动化。
  2. 我可以要求 CRTP 参数在模板参数列表中始终排在第一位,而不是将其包装在一个 Policy1_is类中。这解决了编译时错误,但它失去了覆盖的顺序独立性。

所以看起来我就是高尔夫球手所说的“在俱乐部之间”。哪种解决方案最好?

0 投票
2 回答
284 浏览

c++ - 带有模板叶类的奇怪重复模板

我正在考虑为我的应用程序使用奇怪的重复模板模式。但是,我希望这些类对用户定义的类型进行操作。我想了解是否可以创建类似于下图所示的结构:

上面的代码编译失败,出现以下错误:

'模板类 BaseTrajectoryPoint' 的模板参数列表中参数 1 的类型/值不匹配</p>

有没有其他解决问题的方法?我想使用静态多态性,但我更愿意在基类中定义所有可能的方法。

0 投票
1 回答
416 浏览

c++ - C++ 中带有混入的奇怪循环继承

在这里解读循环继承的好方法是什么?

它失败(gcc 4.7.0),因为在尝试从它继承TrafficLight时是不完整的类型。HasImportance

真正的问题是 HasImportance 需要知道 neighbors(). 如果HasImportance继承自 Node,则它认为neighbors()返回 的列表 Node*,而不是TrafficLight*,因此不知道它可以调用receive_importance()这些项目。HasImportance如果根本不继承类似的问题。

顺便说一句,我想做的是做一些混合来帮助轻松定义各种不同类型的图形,并分别对每个混合进行单元测试。例如,我应该能够通过编写类似class TrafficLight : public HasImportance, HasState<3>, virtual Node { }.

我想出了三种方法来解决这个问题,但看起来都很丑。(1) static_cast<NodeType*>。(2)TrafficLight将其传递 thisHasImportance它的构造函数。这样, HasImportance根本不需要继承;它只存储一个指向 (ahem) 本身的指针,模板参数提供指针的类型。(3) 制作Node一个类模板,如下所示:

编译后并没有引入 的无偿副本this,但似乎……有点太好奇了。

这里有代码气味吗?我应该以完全不同的方式处理这些图表吗?

0 投票
1 回答
2538 浏览

c++ - 如何将模板参数传递给 CRTP?

在以下代码中:

如何编写 CRPTInt 以便我可以传入模板化参数,然后将在派生定义中继续?

谢谢,

吉姆