How to prevent impl details from being in the header file when a global function needs a pointer to the impl?

132 views Asked by At

I'm using the pimpl idiom heavily in my code, mostly to reduce compilation time.

I have a situation where I'm calling into a C library. I have a C++ wrapper class which has its interface, and the gory details are all in the impl, of course:

class some_class {
public:
    void some_init();
    ...
private:
    class impl;
    std::unique_ptr<impl> m_pimpl;
}

In the cpp file I have to register a callback with the C library where I get to give it a pointer. I want to forward this function call to the corresponding member function. The client (i.e. the user of this function) doesn't have to know about this detail at all:

static void from_c_func(void *ptr_to_class_impl) {
    static_cast<some_class::impl *>(ptr_to_class_impl)->from_c_func();
}

void some_class::some_init() {
    create_c_thing(static_cast<void *>(this->m_pimpl.get()), from_c_func);
}

The problem is that some_class::impl is declared private. I can only think of imperfect solutions:

  1. Make the class impl; public in the header file. This is not ideal because it really should be private - it just happens to be an implementation detail that a non-class function needs to see it.
  2. Put from_c_func in the header file and friend it. This is not ideal because the implementation details of some_class are leaking out. Changing the implementation may require changing the header file, which would then recompile a lot of things which don't need recompilation, which would make me unhappy.
  3. Give from_c_func a pointer to some_class itself, and then call a function on some_class. This would require putting that function in the header file, which is again, an implementation detail - and it would have to be public anyway for the non-friend function to call it.

What to do? My best bet so far seems to be #1, but is there any better way?

1

There are 1 answers

1
Jarod42 On BEST ANSWER

You may move your function in impl

static void some_class::impl::from_c_func(void *ptr_to_class_impl) {
    static_cast<some_class::impl *>(ptr_to_class_impl)->from_c_func();
}