首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用继承而不是类型防御来进行前向声明性,从而使回调变得复杂。

使用继承而不是类型防御来进行前向声明性,从而使回调变得复杂。
EN

Stack Overflow用户
提问于 2011-11-17 22:15:27
回答 3查看 303关注 0票数 0

不太清楚这里的标题怎么表达。

问题是我有一个类模板:

代码语言:javascript
复制
template<various parameters> struct Base { ... };

然后,我有一组来自于它的开放的类:

代码语言:javascript
复制
struct A: public Base<some arguments> { ... };
struct B: public Base<other arguments> { ... };
struct C: public Base<different arguments> { ... };
...

重要的是,派生类除了修复模板参数--非成员函数,尤其是成员变量之外,不会向基本库添加任何内容。所以它们的二进制表示都应该是相同的。我使用继承而不是类型防御的唯一原因是,我希望能够转发--声明A、B、C等(或者更准确地说,A、B、C等是由客户端使用提供的宏定义的,为了方便,我希望他们能够转发--声明)。拥有A、B、C等的根本原因是为了避免一直用手写出模板参数。

问题是Base有一些函数将回调作为参数,回调应该将对类本身的引用作为参数。

因此,我希望具有如下回调函数:

代码语言:javascript
复制
void foo (A&, ...);
void bar (B&, ...);

以此类推。在Base中回调函数的实现中,我想将*作为回调的参数传递。非常明智的是,C++不允许我这样做,因为在预期派生类的地方传递基类通常不安全。但是在这种特殊的情况下,它不应该是一个问题,因为派生类不会给基添加任何东西,而只是被使用而不是类型防御。

看来我有三个标准:

  • 我希望“类型防御”是可声明的。
  • 我需要能够将基类传递给回调。
  • 我希望能够使用'typedefs‘而不是基类来声明回调。

它们是互不相容的。(第三个标准同样是为了方便客户端,因为每次手动将模板参数写入基类将是非常冗长的,而不想这样做是使用“typedefs”的全部原因。)

我认为有三种解决办法:

  • 放下第一个或第三个标准。
  • 一种丑陋而复杂的方案,我用它来检查回调函数所期望的是哪种参数,并验证它是否是基的伪类型胡枝子(通过检查same是相同的,或者由SFINAE检查它是从基派生的,或者检查由假名生成的宏插入的某种令牌,或者类似的东西),然后执行强制转换。

还有更好的吗?

(允许使用C++11。)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-11-17 22:22:36

使用CRTP成语并在模板参数中传递派生类。对于回调,只需将*this转换为派生类型即可。

代码语言:javascript
复制
template<class Derived, other params...>
struct Base{
    template<class F>
    void do_callback_stuff(F func){
        func(static_cast<Derived&>(*this), ....);
    }
};

struct A : public Base<A, other args...>{};
票数 4
EN

Stack Overflow用户

发布于 2011-11-17 22:53:07

正如其他人所建议的那样,CRTP可以是一种解决办法。

但是,您还应该重新考虑回调何时以及为什么需要对对象的引用,而对象的专用调用方并不详细地了解它自己。我想说的是:“类模板在实例化之前并不了解它自己的详细信息”。

因此,检查回调可能具有的与调用者对象引用(实例化的类模板对象)相关的使用模式。并提取公共基类或基接口。

然后从该基派生类模板:

代码语言:javascript
复制
struct BaseInterface {

    // HERE, declare anything, that callbacks may use

    virtual void foo() = 0;
};

template<various parameters>
struct Base : public BaseInterface { ... };


void some_callback( BaseInterface& caller, ... );
票数 2
EN

Stack Overflow用户

发布于 2011-11-17 22:33:10

也许将奇怪地反复出现的模板模式和隐式转换结合在一起就可以做到这一点:

代码语言:javascript
复制
template<typename Derived, various parameters> struct Base
{
  operator Derived&() { return static_cast<Derived&>(*this); }
  operator Derived const&() const { return static_cast<Derived const&>(*this); }
  other stuff;
};

struct A: Base<A, some arguments> {};
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8175155

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档