Boost logo

Boost :

From: Joel de Guzman (joel_at_[hidden])
Date: 2005-06-30 07:37:34


Hi,

I like the idea behind the Interfaces Library:
     http://www.kangaroologic.com/interfaces/

I need one now. I dislike the macro-based Interface
Definition Language, however. I find it utterly ugly
especially because interfaces should be immediately
readable. IMO, the macro-based IDL is not.

Here's another take (prototype) at a macro less
implementation of the interfaces (see attached).
Tested on VC7.1, g++ and Comeau. The biggest advantage
is that the same C++ member function interface syntax
is retained. This makes it very easy to understand and
even allows documentation extraction tools like Doxygen
to work as usual. A disadvantage is that there is some
unavoidable redundancy-- a lesser price to pay, IMO.

Here's a client side example:

struct foo : member_function<int(int)> {};
struct bar : member_function<int(char const*)> {};

// a baz "interface"
class baz : interface<foo, bar>
{
public:

     template <class T>
     baz(T& x) : construct(x) {}

     int foo(int x)
     { return this->call< ::foo>(x); }

     int bar(char const* x)
     { return this->call< ::bar>(x); }
};

struct some_baz
{
     int impl(foo, int x) { return x + 1; }
     int impl(bar, char const* s) { return std::strlen(s); }
};

struct another_baz
{
     int impl(foo, int x) { return x - 1; }
     int impl(bar, char const* s) { return -std::strlen(s); }
};

int
main()
{
     some_baz f;
     baz p = f;
     std::cout << "p.foo(3) = " << p.foo(3) << std::endl;
     std::cout << "p.bar(\"hi\") = " << p.bar("hi") << std::endl;

     another_baz f2;
     p = f2;
     std::cout << "p.foo(3) = " << p.foo(3) << std::endl;
     std::cout << "p.bar(\"hi\") = " << p.bar("hi") << std::endl;
}

Regards,

-- 
Joel de Guzman
http://www.boost-consulting.com
http://spirit.sf.net

#include <iostream>
#include <string>
#include <cstring>
#include <boost/spirit/fusion/sequence/tuple.hpp>
#include <boost/spirit/fusion/sequence/at.hpp>

using namespace boost::fusion;

template <class Sig>
struct member_function;

template <class RT, class A0>
struct member_function<RT(A0)>
{
    typedef RT return_type;
    typedef A0 arg0_type;
    typedef RT(*pointer_type)(void*, A0);
};

template <class F0, class F1>
struct interface
{
    typedef tuple<
        typename F0::pointer_type
      , typename F1::pointer_type>
    vtable_type;
 
    template <class T>
    struct functions
    {
        template <typename F>
        struct forward
        {
            typedef typename F::return_type return_type;
            typedef typename F::arg0_type arg0_type;

            static return_type
            call(void* p, arg0_type x)
            {
                return static_cast<T*>(p)->impl(F(), x);
            }
        };
        
        static typename interface<F0, F1>::vtable_type const*
        table()
        {
            static typename interface<F0, F1>::vtable_type
                vtable(
                    &forward<F0>::call
                  , &forward<F1>::call);
            return &vtable; // a singleton
        }
    };

    template <class T>
    interface(T& x)
    : vtable(functions<T>::table())
    , obj(&x)
    {}

    typedef interface<F0, F1> construct;
    
    typename boost::fusion::meta::at_c<vtable_type const, 0>::type
    find(F0) const
    {
        return boost::fusion::at<0>(*vtable);
    }

    typename boost::fusion::meta::at_c<vtable_type const, 1>::type
    find(F1) const
    {
        return boost::fusion::at<1>(*vtable);
    }

    template <typename F>
    typename F::return_type
    call(typename F::arg0_type x)
    {
        return find(F())(const_cast<void*>(obj), x);
    }
       
    vtable_type const* vtable;
    void const* obj;
};

///////////////////////////////////////////////////////////////
//
// Client Code
//
///////////////////////////////////////////////////////////////

struct foo : member_function<int(int)> {};
struct bar : member_function<int(char const*)> {};

// a baz "interface"
class baz : interface<foo, bar>
{
public:

    template <class T>
    baz(T& x) : construct(x) {}

    int foo(int x)
    { return this->call< ::foo>(x); }

    int bar(char const* x)
    { return this->call< ::bar>(x); }
};

struct some_baz
{
    int impl(foo, int x) { return x + 1; }
    int impl(bar, char const* s) { return std::strlen(s); }
};

struct another_baz
{
    int impl(foo, int x) { return x - 1; }
    int impl(bar, char const* s) { return -std::strlen(s); }
};

int
main()
{
    some_baz f;
    baz p = f;
    std::cout << "p.foo(3) = " << p.foo(3) << std::endl;
    std::cout << "p.bar(\"hi\") = " << p.bar("hi") << std::endl;

    another_baz f2;
    p = f2;
    std::cout << "p.foo(3) = " << p.foo(3) << std::endl;
    std::cout << "p.bar(\"hi\") = " << p.bar("hi") << std::endl;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk