2

デバイススローシリアルポートとのプロトコル通信を実装する必要があります。プロトコルはバイナリ ベースで、パケットの種類と長さを含むヘッダー、オプションの本文、およびチェックサムがあります。

v110_xp ツールセットを使用して Visual C++ 2012 で C++11 を使用しています。

それを実装する最初の試みは、次のクラスを使用することです。

PacketOutAPacketOutBPacketOutCはすべて共通のインターフェイスを持つクラスであり、メソッドは 2 つだけbegin()ですend()

私は response packet 用のインターフェース、共通スタッフと派生物を実装するIPacketIn派生クラスなどを持っています。PacketInPacketInAPacketInB

このクラス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;
};

しかし、受け取ったメソッドに問題があります。この状況で戻り値の型を推測するにはどうすればよいですか?

このデザインは良い選択ですか?同じことをするより良い方法はありますか?

4

1 に答える 1

3

関数は静的ではないため、send()呼び出すにはインスタンスが必要です。

を使用std::declval<>()してダミー インスタンスを作成できます。これは未評価のコンテキストでありdeclval()、参照型へのキャストのみを行うため、クラスは実際にはインスタンス化されません。

#include <utility>

template < typename PacketOutKind >
    auto receive( const PacketOutKind& p ) -> 
//          ^^
//          Totally unrelated spelling issue :)
        decltype( std::declval< Controller< PacketOutKind > >().send( p ) )
//                ^^^^^^^^^^^^
{
    // ...
}
于 2013-06-14T14:06:32.500 に答える