CRTP:基于派生类内容启用基类中的方法

2024-01-06

有没有办法从 CRTP 基类查询派生类的内容,与 SFINAE 一起使用来启用或禁用基类方法?

我想要完成的事情可能如下所示:

template<typename Derived>
struct base
{
    struct foo {};
    struct bar {};

    void dispatch(int i)
    {
        switch (i) {
        case 0: dispatch(foo{}); break;
        case 1: dispatch(bar{}); break;
        default: break;
        }
    }

    // catch all for disabled methods
    template<typename T> void dispatch(T const&) {}

    std::enable_if</* magic that checks if there is in fact Derived::foo(foo) */>
      dispatch(foo f)
    {
        static_cast<Derived*>(this)->foo(f);
    }
    std::enable_if</* magic that checks if there is in fact Derived::bar(bar) */>
      dispatch(bar b)
    {
        static_cast<Derived*>(this)->bar(b);
    }
};

struct derived: public base<derived>
{
    // only foo in this one
    void foo(foo) { std::cout << "foo()\n"; }
};

只是尝试使用Derived::foo inside enable_if导致错误,引用不完整类(派生类)的无效使用。


有没有办法从 CRTP 基类查询派生类的内容,与 SFINAE 一起使用来启用或禁用基类方法?

是的。它遵循一个最小的工作示例:

#include<iostream>

template<typename D>
class base {
    template<typename T = D>
    auto dispatch(int) -> decltype(std::declval<T>().foo(), void()) {
        static_cast<T*>(this)->foo();
    }

    void dispatch(char) {
        std::cout << "base" << std::endl;
    }

public:
    void dispatch() {
        dispatch(0);
    }
};

struct derived1: base<derived1> {
    void foo() {
        std::cout << "derived1" << std::endl;
    }
};

struct derived2: base<derived2> {};

int main() {
    derived1 d1;
    derived2 d2;
    d1.dispatch();
    d2.dispatch();
}

添加要转发的参数很简单,我更喜欢让示例尽可能简单。
看到它正在运行wandbox http://melpon.org/wandbox/permlink/RYGSpwrzxRQnYmIX.

从上面的代码片段中可以看出,基本思想是使用标记分派和重载方法来启用或禁用基类中的方法,并使用派生类中的方法(如果存在)。

简单地尝试在enable_if内部使用Derived::foo会导致错误,引用不完整类(派生类)的无效使用。

那是因为Derived当你尝试使用它时实际上是不完整的。标准说:

在类说明符的结束}处,类被视为完全定义的对象类型(或完整类型)。

在您的情况下,派生类有一个基类模板,并且出于明显的原因,在后者的实例化过程中,前者不是完整的类型。
而且,Derived不是你的 sfinae 表达式中的实际类型并且(让我说)sfinae 不起作用在这种情况下。这就是我在示例中执行以下操作的原因:

template<typename T = D>
auto dispatch(int) -> decltype(std::declval<T>().foo(), void()) {
    static_cast<T*>(this)->foo();
}

当然,decltypesfinae 表达式也以这种方式使用。你可以做类似的事情std::enable_if_t如果你更喜欢。我发现这个版本更容易阅读和理解。


话虽这么说,您可以通过虚拟方法获得相同的结果。如果您没有充分的理由不这样做,请使用它。


为了完整起见,您的示例已更新为上述技术:

#include<iostream>

template<typename Derived>
struct base
{
    struct foo {};
    struct bar {};

    void dispatch(int i)
    {
        switch (i) {
        case 0: dispatch(0, foo{}); break;
        case 1: dispatch(0, bar{}); break;
        default: break;
        }
    }

    template<typename T>
    void dispatch(char, T const&) {}

    template<typename D = Derived>
    auto dispatch(int, foo f)
    -> decltype(std::declval<D>().foo(f), void())
    {
        static_cast<D*>(this)->foo(f);
    }

    template<typename D = Derived>
    auto dispatch(int, bar b)
    -> decltype(std::declval<D>().bar(b), void())
    {
        static_cast<D*>(this)->bar(b);
    }
};

struct derived: public base<derived>
{
    void foo(foo) { std::cout << "foo" << std::endl; }
};

int main() {
    derived d;
    d.dispatch(0);
    d.dispatch(1);
}

看到它wandbox http://melpon.org/wandbox/permlink/tZroWbTpLimF4Krd.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CRTP:基于派生类内容启用基类中的方法 的相关文章

  • 如何在c++中读取pcap文件来获取数据包信息?

    我想用 C 编写一个程序来读取 pcap 文件并获取数据包的信息 例如 len sourc ip flags 等 现在我找到了如下代码 我认为它会帮助我获取信息 但是我有一些疑问 首先我想知道应该将哪个库添加到我的程序中 然后什么是 pca
  • 如何将 protobuf-net 与不可变值类型一起使用?

    假设我有一个像这样的不可变值类型 Serializable DataContract public struct MyValueType ISerializable private readonly int x private readon
  • 计算 Richtextbox 中所有单词的最有效方法是什么?

    我正在编写一个文本编辑器 需要提供实时字数统计 现在我正在使用这个扩展方法 public static int WordCount this string s s s TrimEnd if String IsNullOrEmpty s re
  • 在 LINQ 中按 Id 连接多表和分组

    我想按categoryId显示列表产品的名称组 这是我的代码 我想要我的视图显示结果 Desktop PC HP Red PC Dell Yellow PC Asus Red SmartPhone Lumia 720 Blue 我的组模型
  • 复制目录内容

    我想将目录 tmp1 的内容复制到另一个目录 tmp2 tmp1 可能包含文件和其他目录 我想使用C C 复制tmp1的内容 包括模式 如果 tmp1 包含目录树 我想递归复制它们 最简单的解决方案是什么 我找到了一个解决方案来打开目录并读
  • 如何区分用户点击链接和页面自动重定向?

    拥有 C WebBrowser control http msdn microsoft com en us library system windows forms webbrowser aspx在我的 WinForms 应用程序中 并意识
  • 获取两个工作日之间的天数差异

    这听起来很简单 但我不明白其中的意义 那么获取两次之间的天数的最简单方法是什么DayOfWeeks当第一个是起点时 如果下一个工作日较早 则应考虑在下周 The DayOfWeek 枚举 http 20 20 5B1 5D 3a 20htt
  • 如何使用 LINQ2SQL 连接两个不同上下文的表?

    我的应用程序中有 2 个数据上下文 不同的数据库 并且需要能够通过上下文 B 中的表的右连接来查询上下文 A 中的表 我该如何在 LINQ2SQL 中执行此操作 Why 我们正在使用 SaaS 产品来跟踪我们的时间 项目等 并希望向该产品发
  • 在 C 中初始化变量

    我知道有时如果你不初始化int 如果打印整数 您将得到一个随机数 但将所有内容初始化为零似乎有点愚蠢 我问这个问题是因为我正在评论我的 C 项目 而且我对缩进非常直接 并且它可以完全编译 90 90 谢谢 Stackoverflow 但我想
  • 在 Visual Studio 2010 中从 Fortran 调用 C++ 函数

    我想从 Fortran 调用 C 函数 为此 我在 Visual Studio 2010 中创建了一个 FORTRAN 项目 之后 我将一个 Cpp 项目添加到该 FORTRAN 项目中 当我要构建程序时出现以下错误 Error 1 unr
  • 标准化 UTF-8 到底是什么?

    The 重症监护室项目 http userguide icu project org transforms normalization 现在也有一个PHP库 http us php net manual en class normalize
  • 在一个平台上,对于所有数据类型,所有数据指针的大小是否相同? [复制]

    这个问题在这里已经有答案了 Are char int long 甚至long long 大小相同 在给定平台上 不能保证它们的大小相同 尽管在我有使用经验的平台上它们通常是相同的 C 2011 在线草稿 http www open std
  • 使用自定义堆的类似 malloc 的函数

    如果我希望使用自定义预分配堆构造类似 malloc 的功能 那么 C 中最好的方法是什么 我的具体问题是 我有一个可映射 类似内存 的设备 已将其放入我的地址空间中 但我需要获得一种更灵活的方式来使用该内存来存储将随着时间的推移分配和释放的
  • C#:帮助理解 UML 类图中的 <>

    我目前正在做一个项目 我们必须从 UML 图编写代码 我了解 UML 类图的剖析 但我无法理解什么 lt
  • 为什么 std::strstream 被弃用?

    我最近发现std strstream已被弃用 取而代之的是std stringstream 我已经有一段时间没有使用它了 但它做了我当时需要做的事情 所以很惊讶听到它的弃用 我的问题是为什么做出这个决定 有什么好处std stringstr
  • 动态添加 ASP.Net 控件

    我有一个存储过程 它根据数据库中存储的记录数返回多行 现在我想有一种方法来创建 div 带有包含该行值的控件的标记 如果从数据库返回 10 行 则 10 div 必须创建标签 我有下面的代码来从数据库中获取结果 但我不知道如何从这里继续 S
  • 使用 C# 读取 Soap 消息

  • C++ 函数重载类似转换

    我收到一个错误 指出两个重载具有相似的转换 我尝试了太多的事情 但没有任何帮助 这是那段代码 CString GetInput int numberOfInput BOOL clearBuffer FALSE UINT timeout IN
  • 按 Esc 按键关闭 Ajax Modal 弹出窗口

    我已经使用 Ajax 显示了一个面板弹出窗口 我要做的是当用户按 Esc 键时关闭该窗口 这可能吗 如果有人知道这一点或以前做过这一点 请帮助我 Thanks 通过以下链接 您可以通过按退出按钮轻松关闭窗口 http www codepro
  • Oracle Data Provider for .NET 不支持 Oracle 19.0.48.0.0

    我们刚刚升级到 Oracle 19c 19 3 0 所有应用程序都停止工作并出现以下错误消息 Oracle Data Provider for NET 不支持 Oracle 19 0 48 0 0 我将 Oracle ManagedData

随机推荐