
#include <iostream>

struct Client
{
    template<class Request, class Response>
    void sendRequest(const Request& q , Response& a)
    {
        std::cout << q << " " << a << "\n";
    }
};

template<class Q, class A, class ... Rest>
struct IClient : public virtual IClient<Rest ...>
{
    using IClient<Rest ...>::sendRequest;
    virtual void sendRequest(const Q& , A&) = 0;

    ~IClient() = default;
};

template<class Q, class A>
struct IClient<Q, A>
{
    virtual void sendRequest(const Q& , A&) = 0;
    ~IClient() = default;
};

void foo(IClient<int, char, int, int, double, float>& client)
{
    int i = 10;
    char c = 'd';
    double d = 3.14;
    float f = 100.5f;
    client.sendRequest(i, c);
    client.sendRequest(i, i);
    client.sendRequest(d, f);
}

template<class Q, class A, class ... Rest>
struct ClientAdapter: public virtual IClient<Q, A, Rest ...>, public ClientAdapter<Rest ...>
{
    using ClientAdapter<Rest ...>::sendRequest;

    Client& client;
    ClientAdapter(Client& c) : ClientAdapter<Rest...>(c), client(c)
    {

    }

    void sendRequest(const Q& q, A& a) override
    {
        client.sendRequest(q, a);
    }

    ~ClientAdapter() = default;
};

template<class Q, class A>
struct ClientAdapter<Q, A> : public virtual IClient<Q, A>
{
    Client& client;
    ClientAdapter(Client& c) : client(c) { }

    void sendRequest(const Q& q, A& a) override
    {
        client.sendRequest(q, a);
    }

    ~ClientAdapter() = default;
};

int main()
{
    Client client;
    ClientAdapter<int, char, int, int, double, float> adapter(client);
    foo(adapter);
}
