CRTP 避免虚拟成员函数开销

发布于 2024-11-25 10:43:02 字数 1085 浏览 3 评论 0原文

CRTP以避免动态多态性中,提出了以下解决方案来避免开销虚拟成员函数并强加一个特定的接口:

template <class Derived>
struct base {
  void foo() {
    static_cast<Derived *>(this)->foo();
  };
};

struct my_type : base<my_type> {
  void foo() {}; // required to compile. < Don't see why
};

struct your_type : base<your_type> {
  void foo() {}; // required to compile. < Don't see why
};

然而,派生类似乎不需要定义来编译,因为它继承了一个定义(代码可以在不定义 my_type::foo 的情况下编译良好)。事实上,如果提供了函数,则在使用派生类时将不会调用基函数。

所以问题是,以下代码替换是否可以接受(并且标准?):

template <class Derived>
struct base {
  void foo() {
    // Generate a meaningful error if called
    (void)sizeof( Derived::foo_IS_MISSING );
  };
};

struct my_type : base<my_type> {
  void foo() {}; // required to compile.
};

struct your_type : base<your_type> {
  void foo() {}; // required to compile.
};

int main() {
  my_type my_obj;
  my_obj.foo(); // will fail if foo missing in derived class
}

In CRTP to avoid dynamic polymorphism, the following solution is proposed to avoid the overhead of virtual member functions and impose a specific interface:

template <class Derived>
struct base {
  void foo() {
    static_cast<Derived *>(this)->foo();
  };
};

struct my_type : base<my_type> {
  void foo() {}; // required to compile. < Don't see why
};

struct your_type : base<your_type> {
  void foo() {}; // required to compile. < Don't see why
};

However it seems that the derived class does not require a definition to compile as it inherits one (the code compiles fine without defining a my_type::foo). In fact if a function is provided, the base function will not be called when using the derived class.

So the question is, is the following code replacement acceptable (and standard?):

template <class Derived>
struct base {
  void foo() {
    // Generate a meaningful error if called
    (void)sizeof( Derived::foo_IS_MISSING );
  };
};

struct my_type : base<my_type> {
  void foo() {}; // required to compile.
};

struct your_type : base<your_type> {
  void foo() {}; // required to compile.
};

int main() {
  my_type my_obj;
  my_obj.foo(); // will fail if foo missing in derived class
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

墨小墨 2024-12-02 10:43:02

据我了解,这种模式的要点是,您可以简单地将参数传递为 template碱基& 并且您的接口由 base 中的(非虚拟)函数定义。如果您没有要定义的接口(正如您在问题的第二部分中所建议的那样),那么首先就不需要任何这些。

请注意,您并不是像纯虚函数那样“强加”一个接口,而是提供一个接口。由于一切都在编译时解决,因此“强加”并不是一个强烈的要求。

The whole point of this pattern is, as far as I understand, that you can pass arguments simply as template <typename T> base<T> & and your interface is defined by (non-virtual) functions in base<T>. If you don't have an interface that you want to define (as you are suggesting in the second part of your question), then there's no need for any of this in the first place.

Note that you are not "imposing" an interface like with pure virtual functions, but rather you are providing an interface. Since everything is resolved at compile time, "imposing" isn't such a strong requirement.

情话难免假 2024-12-02 10:43:02

在替换代码中,您无法在 base 上“多态”调用 foo

In your replacement code you can't "polymorphically" call foo on a base<T>.

凌乱心跳 2024-12-02 10:43:02

然而,派生类似乎不需要定义来编译,因为它继承了定义代码可以在不定义 my_type::foo 的情况下正常编译)。

C++ 是懒惰的:如果您实际上不使用它,它不会尝试创建 base::foo() 。
但是,如果您尝试使用它,那么它将被创建,如果失败,则会出现编译错误。
但就你而言, base::foo() 可以很好地实例化:

template <class Derived>
struct base {
  void foo() {
    static_cast<Derived *>(this)->foo();
  };
};

struct my_type : base<my_type> {};

void func() {
    my_type m;
    static_cast<base<my_type>& >(m).foo();
}

将编译得很好。当编译器出现
static_cast(this)->foo(),它会尝试查找 my_type 中可访问的 foo()。有一个:它称为 base::foo(),它是从公共继承的类中公开的。所以 base::foo() 调用 base::foo(),并且您会得到无限递归。

However it seems that the derived class does not require a definition to compile as it inherits one (the code compiles fine without defining a my_type::foo).

C++ is lazy : it will not try to make base<my_type>::foo() if you do not actually use it.
But if you try to use it, then it will be created and if that fails, compilation errors will flow.
But in your case, base<my_type>::foo() can be instanciated just fine :

template <class Derived>
struct base {
  void foo() {
    static_cast<Derived *>(this)->foo();
  };
};

struct my_type : base<my_type> {};

void func() {
    my_type m;
    static_cast<base<my_type>& >(m).foo();
}

will compile just fine. When the compiler is presented with
static_cast(this)->foo(), it will try to find a foo() that is accessible in my_type. And there is one: it's called base<my_type>::foo(), which is public from a publicly inherited class. so base<my_type>::foo() calls base<my_type>::foo(), and you get an infinite recursion.

披肩女神 2024-12-02 10:43:02

不,想象一下以下情况:

template <typename T>
void bar(base<T> obj) {
   obj.foo();
}

base<my_type> my_obj;
bar(my_obj);

将调用 Base 的 foo 而不是 my_type 的...

这样做,您将收到错误消息:

template <class Derived>
struct base {
  void foo() {
    sizeof(Derived::foo);
    static_cast<Derived *>(this)->foo();
  };
};

但我必须承认,我不确定这在 GCC 以外的编译器中如何工作,仅通过测试海湾合作委员会。

No, imagine the following situation:

template <typename T>
void bar(base<T> obj) {
   obj.foo();
}

base<my_type> my_obj;
bar(my_obj);

Base's foo will be called instead of my_type's...

Do this, and you will get your erro message:

template <class Derived>
struct base {
  void foo() {
    sizeof(Derived::foo);
    static_cast<Derived *>(this)->foo();
  };
};

But I must confess I am not sure how this will work in compilers other than GCC, tested only with GCC.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文