问题重构奇怪的重复模板模式

发布于 2024-12-28 22:02:58 字数 910 浏览 1 评论 0原文

以下代码无法在 g++ 4.6.1 上编译:

template<class Base>
struct GetBase {
  Base * getBase() {
    return static_cast<Base *>(this);
  }
};

template<class Derived>
struct Parent : private GetBase<Derived> {
  using GetBase<Derived>::getBase;
  int y() {
    return getBase()->x();
  }
};

struct Child : public Parent<Child> {
  int x() {
    return 5;
  }
  int z() {
    return y();
  }
};

出现错误

In member function ‘Base* GetBase<Base>::getBase() [with Base = Child]’:
    instantiated from ‘int Parent<Derived>::y() [with Derived = Child]’
    instantiated from here
error: ‘GetBase<Child>’ is an inaccessible base of ‘Child’

将 static_cast 更改为 reinterpret_cast 将使代码能够编译并且在这种情况下可以工作,但我想知道这是否在所有情况下都是可接受的解决方案?即,指向基类的指针是否与此不同?我假设在多重继承中,如果父母有数据成员,可能会发生这种情况?如果 GetBase 是第一个超类,那么 this 指针是否保证相等?

The following code fails to compile on g++ 4.6.1:

template<class Base>
struct GetBase {
  Base * getBase() {
    return static_cast<Base *>(this);
  }
};

template<class Derived>
struct Parent : private GetBase<Derived> {
  using GetBase<Derived>::getBase;
  int y() {
    return getBase()->x();
  }
};

struct Child : public Parent<Child> {
  int x() {
    return 5;
  }
  int z() {
    return y();
  }
};

with the error

In member function ‘Base* GetBase<Base>::getBase() [with Base = Child]’:
    instantiated from ‘int Parent<Derived>::y() [with Derived = Child]’
    instantiated from here
error: ‘GetBase<Child>’ is an inaccessible base of ‘Child’

Changing the static_cast to a reinterpret_cast will get the code to compile and it will work in this case, but I'm wondering if this is an acceptable solution in all cases? i.e., is it ever the case that a pointer to a base class is not the same as this? I'm assuming with multiple inheritance this may happen if the parents have data members? If GetBase is the first superclass, are the this pointers guaranteed to be equal?

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

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

发布评论

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

评论(2

像极了他 2025-01-04 22:02:58

我想知道这是否在所有情况下都是可接受的解决方案?

不。(见下文)

是否存在指向基类的指针是这样的情况与此不一样吗?

是的。

  • 通过多重继承,基类不能期望具有相同的地址。

  • 根据编译器的不同,具有 vtable 指针的派生类可能与没有 vtable 指针的基类具有不同的 this

    根据

当显式向上转换为基数时,static_cast 是适当的 C++ 转换。

I'm wondering if this is an acceptable solution in all cases?

No. (See below)

is it ever the case that a pointer to a base class is not the same as this?

Yes.

  • With multiple inheritance, the base classes can not be expected to have the same address.

  • Depending on the compiler, a derived class with a vtable pointer may not have the same this as a base class that has no vtable pointer.

When explicitly upcasting to a base, static_cast is the appropriate C++ cast.

无人问我粥可暖 2025-01-04 22:02:58

一个好问题;它让我了解了有关 static_cast 的新知识。

我认为下面的代码实现了您想要的:为 CRTP 提供一个基类,其中的成员函数将 this 转换为 Derived 类型,但仅使其可供该基类的直接后代访问。它使用 GCC 4.3.4(在 ideone 测试)和 Clang(在 llvm.org 测试)进行编译。抱歉,我无法抗拒更改我觉得令人困惑的名称。

#include <iostream>

template<class Derived>
class CRTP {
protected:
  Derived * derived_this() {
    return static_cast<Derived *>(this);
  }
};

template<class Derived>
struct Parent : public CRTP<Derived> {
private:
  using CRTP<Derived>::derived_this;
public:
  int y() {
    return derived_this()->x();
  }
};

struct Child : public Parent<Child> {
  int x() {
    return 5;
  }
  int z() {
    return y();
  }
};

int main() {
  std::cout << Child().z() << std::endl;
  return 0;
}

此变体之所以有效,是因为继承是公共的,这使得可以将派生类指针标准转换为基类指针,也可以使用 static_cast 进行逆向转换(从基类到派生类) ,CRTP 需要的。代码中的私有继承禁止这样做。因此,我将继承公开,更改了要保护的方法,并通过将 using 声明放入私有部分,在 Parent 中进一步限制访问。

A good question; it caused me to learn something new about static_cast.

I think the following code achieves what you want : provides a base class for CRTP with a member function that casts this to the Derived type, yet only makes it accessible to the direct descendants of this base class. It compiles with GCC 4.3.4 (tested at ideone) and Clang (tested at llvm.org). Sorry, I couldn't resist to changing the names that I find confusing.

#include <iostream>

template<class Derived>
class CRTP {
protected:
  Derived * derived_this() {
    return static_cast<Derived *>(this);
  }
};

template<class Derived>
struct Parent : public CRTP<Derived> {
private:
  using CRTP<Derived>::derived_this;
public:
  int y() {
    return derived_this()->x();
  }
};

struct Child : public Parent<Child> {
  int x() {
    return 5;
  }
  int z() {
    return y();
  }
};

int main() {
  std::cout << Child().z() << std::endl;
  return 0;
}

This variant works because the inheritance is public, which enables the standard conversion of a pointer-to-derived-class to a pointer-to-base-class, and so also the inverse conversion (from base to derived) with static_cast, which CRTP needs. Private inheritance in your code prohibited this. So I made inheritance public, changed the method to be protected, and in Parent further restricted access by putting the using declaration into private section.

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