Вопрос

I've to implement a protocol communication with a device throw serial port. The protocol is binary based where we have an header that containt the kind and the length of the packet, an optional body and a checksum.

I'm using C++11 with Visual C++ 2012 with the v110_xp toolset.

My first attempt to implement it is using the following class:

PacketOutA, PacketOutB, PacketOutC are all classes with a common interface, they have just two method: begin() and end() to access internal data;

I have an interface for response packet IPacketIn, a derived class PacketIn the implement common staff and the derivates PacketInA, PacketInB and so on.

The class Communication is used to allow me to send and recieve data to the communication port.

The ReaderAndValidator class allow me to get validate the recieved packet and get the body.

Dispatcher< T > is used to get the corrisponding input packet from the requestç

PacketInA doPacketA()
{
    PacketA packetA;
    Dispatcher< PacketA > disp( communication );
    PacketInA result = controller.send( packetA );
    return result; // RVO
}

Let's look the snippet of the code:

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

The class Device abstract the operation that I can do on my 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;
};

But I have a problem with the recieved method: how can I deduce the return type in this situation?

Is this design a good choice? Are better way to do the same thing?

Это было полезно?

Решение

The send() function is not static, so you need an instance to invoke it on.

You can use std::declval<>() to create a dummy instance - it's an unevaluated context, and declval() does just a cast to a reference type, so the class won't really be instantiated:

#include <utility>

template < typename PacketOutKind >
    auto receive( const PacketOutKind& p ) -> 
//          ^^
//          Totally unrelated spelling issue :)
        decltype( std::declval< Controller< PacketOutKind > >().send( p ) )
//                ^^^^^^^^^^^^
{
    // ...
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top