#include <iostream>
#include <cassert>

class LibFoo;
class LibBar;

class IfaceA;
class IfaceB;

template <typename LIB> class BaseA;
template <typename LIB> class BaseB;

struct IfaceA
{
    virtual ~IfaceA () {}
    virtual operator BaseA<LibFoo> * () { return 0; }
    virtual operator BaseA<LibBar> * () { return 0; }
    virtual void doSomethingWith (IfaceB &) = 0;
};

struct IfaceB {
    virtual ~IfaceB () {}
    virtual operator BaseB<LibFoo> * () { return 0; }
    virtual operator BaseB<LibBar> * () { return 0; }
};

template <typename LIB>
struct BaseA : IfaceA {
    operator BaseA * () override { return this; }

    void doSomethingWith (IfaceB &b) override {
        doSomethingWithB(b);
    }

    void doSomethingWithB (BaseB<LIB> *b) {
        assert(b);
        doSomethingWithB(*b);
    }

    virtual void doSomethingWithB (BaseB<LIB> &b) = 0;
};

template <typename LIB>
struct BaseB : IfaceB {
    operator BaseB * () override { return this; }
};

struct LibFoo {
    class FooA {};
    class FooB {};
};

struct ConcreteFooA : BaseA<LibFoo> {
    void doSomethingWithB (BaseB<LibFoo> &) override {
        std::cout << "ConcreteFooA::" << __func__ << '\n';
        //...
    }

    LibFoo::FooA a_;
};

struct ConcreteFooB : BaseB<LibFoo> {
    LibFoo::FooB b_;
};

struct LibBar {
    class BarA {};
    class BarB {};
};

struct ConcreteBarA : BaseA<LibBar> {
    void doSomethingWithB (BaseB<LibBar> &) override {
        std::cout << "ConcreteBarA::" << __func__ << '\n';
        //...
    }

    LibBar::BarA a_;
};

struct ConcreteBarB : BaseB<LibBar> {
    LibBar::BarB b_;
};

void
doSomething (IfaceA &a, IfaceB &b)
{
    a.doSomethingWith(b);
}

int
main (void)
{
    ConcreteFooA foo_a;
    ConcreteFooB foo_b;

    doSomething(foo_a, foo_b);

    ConcreteBarA bar_a;
    ConcreteBarB bar_b;

    doSomething(bar_a, bar_b);
}