È possibile avvolgere le prese boost con Pimpl?
-
06-07-2019 - |
Domanda
in un progetto vogliamo avvolgere il socket Boost Asio in un modo, in modo che la classe utilizzante o il wrapping .h non debba includere le intestazioni boost.
Usiamo solitamente puntatori e dichiarazioni forward per le classi wrapped.
Dichiarazione futura:
namespace boost
{
namespace asio
{
namespace ip
{
class udp;
}
}
}
E quindi dichiarando il socket:
scoped_ptr<boost::asio::ip::udp::socket> socket_;
scoped_ptr<boost::asio::ip::udp::endpoint> receiveEp_;
(Se non conosci scoped_ptr, ignoralo, il problema è uguale a un puntatore * standard.)
Ma questo dà un errore del compilatore:
error C2027: use of undefined type 'boost::asio::ip::udp'
Lo capisco perché udp non è in realtà uno spazio dei nomi, ma una classe stessa. Vogliamo solo usare la classe interiore, qualche idea?
Soluzione
Con i tipi interni l'unica opzione è racchiudere tutto. Nasconde gli stessi puntatori con ambito all'interno di una classe dichiarata diretta. Gli utenti vedrebbero solo la tua API e passerebbero in giro i tuoi oggetti invece di oggetti boost.
Nel tuo esempio sebbene scoped_ptr assomigli a dichiarazioni di membri privati, puoi cavartela con semplici:
// 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)
{
}
Altri suggerimenti
Se si utilizza pimpl, perché si inseriscono le variabili membro nell'intestazione? I typedef di socket ed endpoint sono utilizzati nella tua interfaccia? Se non fanno parte della tua interfaccia, l'intero punto del linguaggio del pimpl è che non definisci le variabili membro di una classe nel file header; sono dettagli di implementazione.
Mi aspetto qualcosa di simile nel file di intestazione:
// ...
class MyClass {
public:
MyClass();
// .. Other member functions
private:
struct Imp;
boost::shared_ptr<Imp> m_imp; // This is the only member variable.
};
E poi nel tuo file di implementazione:
#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.
Per rispondere alla tua domanda specifica, i tipi che stai cercando di usare sono typedef nella classe asio udp, quindi il compilatore deve aver visto la definizione di quella classe per usarla.