问题标签 [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 投票
5 回答
1060 浏览

c++ - C++ CRTP 类层次结构

来自维基百科

现在,如果我愿意derived_from_derived,我可以写:

现在假设我只想要一个derived对象。这不起作用:

derived必须是抽象的,还是有办法实例化它?

0 投票
3 回答
1825 浏览

c++ - C++ CRTP 和从基访问派生的嵌套类型定义

编辑:当我为任何感兴趣的人改变我的设计时,我会在这里放一个 github 链接。

背景

我正在用我自己的实现替换boost::intrusive, intrusive_set,因为 64 位编译的侵入集将 3 x 8 字节的指针填充到我的容器节点中。我的容器有 2^16 个节点的限制,因此我可以使用 2x 16 位偏移序数将其降低到每个节点 4 字节(大小减少 6 倍)。

在下面的示例中base是 intrusive-set 容器。该类derived有一个std::vector<container_entry_type<entry_type> >. 显然,在这种间接级别下,我需要在派生中拥有一堆嵌套的 typedef,我想在 base.xml 中引用它们。

ps,容器用于数据描述语言的AST。因此,包含的元素是小型数据类型,并且 3 x 8 字节非常重要。尤其是因为容器用于在紧密循环中验证数据集。

孤立的问题

我想实现以下语义:

但我无法从基础访问嵌套的 typedef。对于这件事,clang 是这么说的:

相反,我必须这样做:

这是实现我的用例的唯一方法吗?它只会让事情变得更加冗长。我想派生也可以从特征派生以节省一些击键。

另一种选择是不使用推导并将逻辑直接连接到当前推导的内容中。但是,我想单独对基础进行单元测试。

0 投票
2 回答
461 浏览

c# - 使用奇怪重复的模板模式时的返回类型

我在我的 C# 项目中使用了奇怪的重复模板模式(CRTP),但我遇到了一些问题。从上面的链接中截取的代码:

美丽的!当我尝试做这样的事情时,问题就出现了:

SomeClass 应该能够返回 Base 类的任何实现,但当然 T 在这里没有任何意义,因为它在另一个类中。将 Derived 而不是 T 编译,但这不是我想要的,因为我也应该能够返回其他类型的项目,只要它们从 Base 派生。此外,GetItem() 可能会根据 SomeClass 对象的状态返回不同类型的对象,因此使 SomeClass 通用也不是解决方案。

我在这里遗漏了一些明显的东西,还是在使用 CRTP 时不能这样做?

0 投票
1 回答
381 浏览

c++ - 如何存储或转发 CRTP 模板类的类型

总体思路:一对班,一个创造工人的经理。每个都接受一组自定义行为的策略。每个策略都有一个影响管理器的部分(进行一些设置)和一个影响工作者的部分(添加需要调用和从宿主工作者类中的函数调用的特定工作函数 - 目前通过 CRTP 完成)

工人中使用的策略将始终反映管理器中的策略。即将manager<foo,bar>创建类型的工人worker<foo_worker,bar_worker>。因此,我想将工作人员策略的类型存储在管理器策略中,以便最终用户不必同时指定两者。

以下代码实现了演示问题的我的代码的简化版本。查看经理类评论。目前(为了编译示例)经理使工人成为硬编码类型。

问题:我如何在类 foo 中记录模板类 foo_worker 的类型,以便管理者可以根据自己的模板参数确定/查找正确的工人类?

typedef foo_worker work_policy;inside ofclass foo不起作用,因为 foo_worker 不是类模板。我尝试了各种包装类以及类型名和模板的组合,但没有运气。我还尝试将 foo_worker 作为 foo 中的嵌套类。

如果我可以避免它,我宁愿不需要 C++11,但如果它从根本上简化了这个问题,我愿意考虑它。

有没有另一种方法来构建这样的系统来避免这个问题?

提前感谢=)

0 投票
2 回答
331 浏览

c++ - 指向成员函数默认值的 CRTP 相关编译器错误

你好呀,

在制作基于 CRTP 的通用包装器来调用任意库函数时,我遇到了一个我无法理解的问题。这是一个非常简化的代码来说明问题:

一切都按预期编译和工作。但是,如果我尝试使用指针TDerived::Foo()作为第二个参数的默认参数TBase::Call(...)

编译器给出了一个语法错误......我感觉它与编译器如何解析代码有关,并且它无法找出指向尚未定义(或实例化)类的函数的指针。TDerived但是,调用构造函数作为第三个参数的默认参数是没有问题的TBase::Call(...)。有人可以就发生的事情给我一个明确的答案吗?为什么派生类 MFP 不被接受,而派生类的对象被接受为默认参数?

谢谢。

编辑:编译器的错误(MSVS2010 命令行编译器):

这是一个语法错误 - 它不能识别TDerived_为 MFP 的默认参数中的类型。这之后还有其他错误,它们都是语法错误,因为函数定义现在格式错误。我就是这么理解的。

编辑:基本上,我不明白为什么我可以使用对象TDerived_作为默认参数,但不能使用指向成员函数的指针作为默认参数。

编辑:好的,这让我发疯了。首先,我改变了typedef TBase< PValue, TDerived > TBase_;它所指出的(谢谢你们,伙计们!)。事实上,它只在 MSVC++ 下编译,因为这个编译器不做两部分解析;即,在codepad.org(使用g++ 4.1.2)上它没有编译。其次,在那之后,我尝试static void Call( PType /*pSomething*/, void(TDerived_::*pFunction)( void ) = &TDerived_::Foo, TDerived_ pDerived = TDerived_() )在codepad.org上使用......它编译并正确运行!所以我现在真的很困惑:人们向我解释了为什么它不正确(而且我无法理解“为什么”(参见我以前的编辑)),现在事实证明 g++ 可以正确编译它......这是否意味着它只是MSVC++ 问题而不是代码?或者从标准的角度来看代码确实存在问题(我看不到它)并且g ++“错误地”接受它(我认为不太可能)?..帮助?!

0 投票
1 回答
313 浏览

c++ - crtp 和类型可见性

我有这个我正在尝试解决的难题,从根本上归结为以下示例:

我可以尝试解释上面的(我尝试了大约三遍并删除了文本!),但基本上要求是:

  1. C必须继承自Btyped with C(利用 CRTP),即B<C<>>
  2. C是唯一可以实例化的A(即A必须用 键入C
  3. A是唯一可以定义的FOOFOO取决于类型CT,关系比呈现的更复杂)

问题(如您在上面的代码中看到的)是该BAR类型仅在内部可用,C并且在实例化时不完整B,因此B看不到BAR模板参数的类型CTC<int>)。不幸的是B,该类型BAR被用作函数的参数和返回类型(即不仅限于函数范围 - 因此我不能简单地将 typedef 移动到函数范围)。

有没有解决的办法?我不能打破上述关系(除非作为最后的手段)。大概使用 c++11,我可以使用auto并解决在 中使用BARtypedef的需要B,但是目前这还不是一个选项。

编辑:继@bitmasks 的评论之后,提供更多信息。

  1. A和中的代码B在不同情况下用于相当多的二进制文件中,在这种情况下唯一独特的情况是C派生自B,在其他情况下,C拥有派生自的事物的实例B
  2. 模板参数可以更改(在Aand中B),只要它们可以默认为不需要更改 and 的现有用途的AB。同一组类型必须可用作默认的模板参数或某些其他机制。

我在这里使用模板只是因为我需要紧耦合并且我需要在不同情况下灵活地使用代码。

组件说明:

  • A最好将其描述为容器,FOO实际上是一个迭代器,它包含的内容由模板参数的 typedef 定义
  • B最好将其描述为包含一组函数的基类,这些函数C. 在前面的案例中,这些组件被传递了一个对派生自的事物的引用B(并且这些事物也归 拥有C),在这种情况下,我提供了对其C自身的引用。

主要的复杂性来自于访问容器,以前和A之间的关系是有一个实例的,但现在是一个实例- 这种语义上的变化打破了将类型注入类的方式。BCC BC B

0 投票
3 回答
5571 浏览

c++ - 具有受保护派生成员的 CRTP

CRTP 模式中,如果我们想将派生类中的实现函数保持为受保护的状态,就会遇到问题。我们必须要么将基类声明为派生类的朋友,要么使用类似的东西(我没有尝试过链接文章中的方法)。是否有其他(简单)方法可以将派生类中的实现函数保持为受保护的状态?

编辑:这是一个简单的代码示例:

上面的代码error: ‘void D::foo()’ is protected用 g++ 4.5.1 给出,但如果protected被替换为public.

0 投票
1 回答
972 浏览

c++ - 使用 CRTP 时如何获取模板参数的大小?

在 VC++10 中,以下示例失败并出现错误 C2027:“使用未定义类型 'X'”。但是 g++ 4.6 编译它就好了。

那么哪一个是对的呢?我将如何做到这一点,以便它适用于主流编译器?

不过这并不是什么大问题,因为 VC++ 仍然允许在 C 的成员函数中使用 sizeof(T)。我只需要重复一些很烦人的长类型定义。

编辑: 我意识到我的例子很糟糕,因为我真正想做的是使用大小作为编译时间常数,以这种方式:

两个编译器都拒绝这个,所以我认为这可能是不可能的,但就像我说的,我仍然可以在函数内部使用 sizeof。我只是希望我不必在每个函数中重复 typedef。

0 投票
2 回答
260 浏览

c++ - CRTP (C++) 的各种错误

我知道我刚刚问了一个关于此的问题,但我无法弄清楚我做错了什么。我只重写了一小部分,找不到任何错误(在父返回子中使用 C++ 函数作为参考)

我的代码:

结果:

我将非常感谢您的回答(我的无能可能是由于睡眠不足:D)

0 投票
2 回答
554 浏览

c++ - 编译器如何评估 `typeid` 运算符?

这是我用来尝试解决这个问题的一些基于 CRTP 的模板代码: Requiring overridden virtual functions to call base implementations。我会在这里发布代码,但是这些行很长,并且在 codepad.org 上更容易阅读(如果需要,我会在这里发布)。当然,它很丑陋,而且有些人为,尽管它确实有效。但我一开始并没有意识到,虽然它可以在 MSVC++ 和 GCC 上编译,但某些模板类型并没有真正定义。我要质疑的部分是顶部函数中的几个长内部if( typeid( Derived(N) ) != typeid( Derived(N-1))(符号符号) 。TBase::OnEvent

你不能typdef使用这些类型,这将是一个编译错误 - 没有足够的派生类可以用这么长的...::TDerived::...链定义类型,所以你会正确地得到编译错误TDerived is not defined in TBase。然而编译器会吃掉它们typeid。当我检查调试器 MSVC++ 编译器输出(带有完整的符号信息)时,似乎所有那些...::TDerived::...不应该真正导致任何类的 long 都typeid被编译器解析为TDerived04类链中的最后一个。...::TDerived::...并且 RTTI 被拉到班级链中的最后一个班级,与我有多少无关。

考虑到 MSVC++ 和 GCC 都是这样做的(尽管我只能通过 codepad.org 访问 GCC),我的问题是下一个:它是否以某种方式定义了行为typeid?那么为什么typedef那些长的...::TDerived::...不解决TDerived04呢?

编辑:我的意思是,我很高兴typedef没有解决TDerived04,这对于任何使用 的人来说都是一场灾难,但为什么和typedef之间存在这种不一致呢?typeidtypedef

编辑:GCC 接受TDerived04::TDerived04::TDerived04::TDerived04 lD4;变量声明。而且类型简单TDerived04到底。是否有折叠范围解析的规则?显然,MSVC++ 和 GCC 似乎都在做同样的事情typeid,但是与 GCC 不同,MSVC++ 无法处理其他情况——它会产生编译错误,需要构造函数的参数。