|
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