其他分享
首页 > 其他分享> > c – Pimpl习语实现取决于模板函数

c – Pimpl习语实现取决于模板函数

作者:互联网

请考虑以下代码.

template参数是一个必须提供函数bar()的处理程序类.

我正在使用Pimpl成语来隐藏Foo的实现细节.在拥有模板参数之前,构造函数定义在foo.cpp中,并且一切都很好.

///////////    
// foo.h
///////////    

class Foo
{
public:
    template <class Handler>
    Foo(Handler& handler);

    void someFunction();

private:
    /** Private implementation details. */
    struct Impl;
    const std::unique_ptr<Impl> m_impl;
};

template <class Handler>
Foo::Foo(Handler& handler) : m_impl{new Impl{handler}}
{
}

///////////    
// foo.cpp
///////////    

#include "foo.h"

/** Encapsulates the private implementation details of Foo. */
struct Foo::Impl
{
public:
    Impl(Handler& handler) : m_handler(handler)
    {
    }

    void someOtherFunction()
    {
        m_handler->bar();
    }

private:
    Handler& m_handler;

    friend class Foo;
};

void Foo::someFunction()
{
    m_impl->someOtherFunction();
}

一旦我介绍了模板参数,我就必须将构造函数放在foo.h中,这会导致以下编译器错误:

分配不完整类型’Foo :: Impl’.

我理解为什么我得到错误,但我想不出一个方法,仍然使用Pimpl成语.

有人可以帮忙吗?

解决方法:

您可以使用或不使用虚函数来解决此问题.第一个选项稍微容易一些:使用虚拟函数,对于Handler

class HandlerBase { .... virtual void bar() = 0; ... };
class Foo { ... std::unique_ptr<HandlerBase> handler; ... };

或者对于Impl

class ImplBase { ... virtual void someFunction() = 0; }
class Foo { ... std::unique_ptr<ImplBase> m_impl; ... }
template<typename Handler> class Impl : public ImplBase { ... Handler& m_handler; ...};

我认为这些实施起来相对简单.你可以看到,当使用HandlerBase时,你甚至不需要pimpl成语.

另一种方法是使用The Impossibly Fast C++ Delegates方法:

class Foo
{
public:
    template <class Handler>
    explicit Foo(Handler& handler)
            : handler(&handler) {
        someFunctionInstance = someFunctionTemplate<Handler>;
    }

    void someFunction() {
        someFunctionInstance(handler);
    }

private:
    typedef void (*SomeFunctionType)(void* handler);

    void* handler;
    SomeFunctionType someFunctionInstance;

    template<typename Handler>
    static void someFunctionTemplate(void* handler) {
        static_cast<Handler*>(handler)->bar();
    }
};

Foo的类型保持独立于Handler.构造函数中的赋值创建someFunctionTemplate的自定义实例,该实例能够调用实际的Handler类型. SomeFunctionInstance是Handler上的模板实例化的结果,但由于它是静态函数,因此它的类型也独立于Handler.

但是这个解决方案很棘手并且包含reinterpret_cast,它仍然是完全类型安全的.

标签:pimpl-idiom,c,templates,template-function
来源: https://codeday.me/bug/20190830/1765131.html