デバイススローシリアルポートとのプロトコル通信を実装する必要があります。プロトコルはバイナリ ベースで、パケットの種類と長さを含むヘッダー、オプションの本文、およびチェックサムがあります。
v110_xp ツールセットを使用して Visual C++ 2012 で C++11 を使用しています。
それを実装する最初の試みは、次のクラスを使用することです。
PacketOutA
、PacketOutB
、PacketOutC
はすべて共通のインターフェイスを持つクラスであり、メソッドは 2 つだけbegin()
ですend()
。
私は response packet 用のインターフェース、共通スタッフと派生物を実装するIPacketIn
派生クラスなどを持っています。PacketIn
PacketInA
PacketInB
このクラスCommunication
を使用して、通信ポートとの間でデータを送受信できるようにします。
このReaderAndValidator
クラスにより、受信したパケットを検証して本文を取得できます。
Dispatcher< T >
リクエストから対応する入力パケットを取得するために使用されます。
PacketInA doPacketA()
{
PacketA packetA;
Dispatcher< PacketA > disp( communication );
PacketInA result = controller.send( packetA );
return result; // RVO
}
コードのスニペットを見てみましょう。
class Communication {
public:
Communication ();
template < typename Iterator >
void send( Iterator first, Iterator last ) const
{
// send from first to last to
}
template< typename Iterator >
std::vector< char > read( Iterator first, Iterator last ) const
{
// read from first to last to
}
private:
// internal stuff
};
class ReaderAndValidator{
public:
ReaderAndValidator( const Communication& comm )
: mComm( comm )
{
}
std::vector< char > read()
{
// read data
return mComm.read( /* params */ );
}
private:
const Communication& mComm;
}
template < typename PacketOut >
class Dispatcher{
Dispatcher()
{
static_assert( false, "unable to instantiate Controller" );
}
};
template <>
class Dispatcher< PacketOutA > {
public:
Dispatcher( const Communication& comm )
: mComm( comm )
{
}
PacketInA send( const PacketOutA & packet ) const
{
mComm.send( std::begin( packet ), std::end( packet ) );
ReaderAndValidator readAndValidate( mComm );
auto body = readAndValidate.read();
// RVO
PacketInA result( std::begin( body ), std::end( body ) );
return result;
}
private:
const Communication& mComm;
};
// same thing for Dispatcher< PacketOutB >, Dispatcher< PacketOutC > and so on
クラスDevice
は、デバイスで実行できる操作を抽象化します
class Device : private boost::noncopyable {
public:
Device ()
{
// init communication
}
void doPacketOutA( int param )
{
PacketOutA packet( param );
recieve( packet );
}
PacketInB doPacketB()
{
PacketOutB packet();
return recieve( packet );
}
private:
template < typename PacketOutKind >
auto recieve( const PacketOutKind& p ) -> decltype( Dispatcher< PacketOutKind >::send( p ) )
{
Dispatcher< PacketOutKind > disp( mCommunication );
return controller.send( p );
}
private:
Communication mCommunication;
};
しかし、受け取ったメソッドに問題があります。この状況で戻り値の型を推測するにはどうすればよいですか?
このデザインは良い選択ですか?同じことをするより良い方法はありますか?