views:

168

answers:

2

Hi,

in a project we want to wrap the Boost Asio socket in a way, that the using class or the wrapping .h does not have to include the boost headers.

We usually use pointers and forward declarations for wrapped classes.

Foward declaration:

namespace boost
{
  namespace asio
  {
    namespace ip
    {
      class udp;
    }
  }
}

And then declaring the socket:

  scoped_ptr<boost::asio::ip::udp::socket> socket_;
  scoped_ptr<boost::asio::ip::udp::endpoint> receiveEp_;

(If you don't know scoped_ptr, ignore it, the problem is equal with a standard * pointer.)

But this gives a compiler error:

error C2027: use of undefined type 'boost::asio::ip::udp'

I understand this is because udp is actually not a namespace, but a class itself. We only want to use the inner class though, any ideas?

+2  A: 

If you are using pimpl, why are you putting member variables in your header? Are the socket and endpoint typedefs used in your interface? If they are not part of your interface, the whole point of the pimpl idiom is that you don't define the member variables of a class in the header file; they are implementation details.

I expect something like this in the header file:

// ...

class MyClass {
public:
    MyClass();
    // .. Other member functions

private:
    struct Imp;
    boost::shared_ptr<Imp> m_imp;   // This is the only member variable.
};

And then in your implementation file:

#include <boost/asio/whatever.hpp>

struct MyClass::Imp
{
    scoped_ptr<boost::asio::ip::udp::socket> socket_;
    scoped_ptr<boost::asio::ip::udp::endpoint> receiveEp_;

    // Remainder of implementation class ...
};

// Other implementation details.

To answer your specific question, the types you are trying to use are typedefs in the asio udp class, so the compiler needs to have seen the definition of that class to use it.

janm
+2  A: 

With inner types your only option is wrapping everything. Hide scoped pointers themselves inside a forward declared class. Users would see only your API and pass around your own objects instead of boost objects.

In your example though scoped_ptr look like private member declarations, you can get away with simple:

// header
class SomeClass 
{ 
public:
    SomeClass();
    // stuff   
private: 
    scoped_ptr<class pimpl_bla> _m; 
};

// source
class pimpl_bla
{
public: 
    scoped_ptr<boost::asio::ip::udp::socket> socket_;
};

SomeClass::SomeClass() 
    :_m(new pimpl_bla)
{ 
}
Eugene
That is, i would have to define all public functions twice.. and SomeClass would simply pass them to pimpl_bla?
Tarnschaf
Depends on what makes sense. I usually use pimpl class as a data member bucket (also it is usually a struct) which are accessed by host class exactly same way as if they are its own. But I'm lazy. :)
Eugene
janm below talks about exactly the same thing BTW.
Eugene
yes, and you are both right but I didn't want to wrap every function because this is just an internal layer, not an API. But if it's the only way to get rid of the transitive boost dependencies..
Tarnschaf
Then you can go the (somewhat) lazy way and use "this->_m->data = 0" instead of "this->data = 0" and keep all the public functions in public class.
Eugene
(unless boost comes in as part of public class interface...)
Eugene