实现采用回调的方法的const和非const版本

时间:2016-02-10 01:34:15

标签: c++ c++11 lambda const-cast

我有以下界面:

struct A {};

struct B
{
    using Cb = std::function<void(A& a)>;
    using ConstCb = std::function<void(const A& a)>;

    virtual void visit(ConstCb cb) const = 0;
    virtual void visit(Cb cb) = 0;
};

B::visit()应列举A类型的所有成员。

现在,由于B :: visit()在派生类时可能会变得复杂,因此复制visit()的实现并不好。迈耶斯建议const-cast(参见here)。

所以方法是:

struct B
{
    using Cb = std::function<void(A& a)>;
    using ConstCb = std::function<void(const A& a)>;

    void visit(Cb cb);
    void visit(ConstCb cb) const;

protected:
    virtual void doVisit(ConstCb) const = 0;
};

void B::f(ConstCb cb) const
{
    doVisit(cb);
}

void B::f(Cb cb)
{
    static_cast<const B*>(this)->f(/* somehow cast cb to ConstCb */);
}

然而,确切地说,丢失的部分似乎是不可能的。我可以使用cb获取std::function::target()的函数指针,然后尝试将其转换为其他类型。但这是不可能的,因为target()不适用于lambda,它们不能转换为函数指针(只有它们有空捕获)。

所以我现在想不出解决方案。有人有什么想法吗?也许整个方法都存在缺陷:D

1 个答案:

答案 0 :(得分:4)

一种选择是引入“蹦床”功能,从非const转换为const

void B::f(Cb cb)
{
    ConstCb trampoline = [&cb] (const A& arg) {
        cb(const_cast<A&>(arg));
    };
    static_cast<const B*>(this)->f(trampoline);
}

换句话说,不要在函数上进行强制转换,只需定义一个对参数执行强制转换的新函数。