forked from boostorg/function_types
libs/function_types/* - check-in
[SVN r37684]
This commit is contained in:
71
example/detail/param_type.hpp
Normal file
71
example/detail/param_type.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Metafunction to compute optimal parameter type for argument forwarding.
|
||||
|
||||
// This header is not an FT example in itself -- it's used by some of them to
|
||||
// optimize argument forwarding.
|
||||
//
|
||||
// For more details see 'fast_mem_fn.hpp' in this directory or the documentation
|
||||
// of the CallTraits utility [1].
|
||||
//
|
||||
//
|
||||
// References
|
||||
// ==========
|
||||
//
|
||||
// [1] http://www.boost.org/libs/utility/call_traits.htm
|
||||
|
||||
#ifndef BOOST_UTILITY_PARAM_TYPE_HPP_INCLUDED
|
||||
#define BOOST_UTILITY_PARAM_TYPE_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/type_traits/add_const.hpp>
|
||||
#include <boost/type_traits/add_reference.hpp>
|
||||
|
||||
#include <boost/mpl/eval_if.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
|
||||
#include <boost/mpl/aux_/lambda_support.hpp>
|
||||
// #include <boost/type_traits/detail/template_arity_spec.hpp>
|
||||
|
||||
// namespace boost
|
||||
namespace example
|
||||
{
|
||||
namespace mpl = boost::mpl;
|
||||
|
||||
// namespace utility
|
||||
// {
|
||||
namespace param_type_detail
|
||||
{
|
||||
template<typename T>
|
||||
struct by_ref_cond
|
||||
{
|
||||
typedef by_ref_cond type;
|
||||
BOOST_STATIC_CONSTANT(bool,value = sizeof(void*) < sizeof(T));
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct add_ref_to_const
|
||||
: boost::add_reference< typename boost::add_const<T>::type >
|
||||
{ };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct param_type
|
||||
: mpl::eval_if< param_type_detail::by_ref_cond<T>
|
||||
, param_type_detail::add_ref_to_const<T>, mpl::identity<T> >
|
||||
{
|
||||
BOOST_MPL_AUX_LAMBDA_SUPPORT(1,param_type,(T))
|
||||
};
|
||||
// }
|
||||
// BOOST_TT_AUX_TEMPLATE_ARITY_SPEC(1,utility::param_type)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
248
example/fast_mem_fn.hpp
Normal file
248
example/fast_mem_fn.hpp
Normal file
@ -0,0 +1,248 @@
|
||||
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// This example implements a very efficient, generic member function wrapper.
|
||||
//
|
||||
//
|
||||
// Detailed description
|
||||
// ====================
|
||||
//
|
||||
// For most platforms C++ runs on (maybe all hardware platforms, as opposed to
|
||||
// virtual machines) there are indirect calls that take more time to execute
|
||||
// than direct ones. Further calling a function usually takes more time than
|
||||
// inlining it at the call site.
|
||||
//
|
||||
// A direct call is a machine instruction that calls a subroutine at a known
|
||||
// address encoded in the instruction itself. C++ compilers usually emit one of
|
||||
// these instructions for each function call to a nonvirtual function (a call to
|
||||
// a virtual function requires either two direct calls or one indirect call).
|
||||
// An indirect call is a machine instruction that calls a subroutine at an
|
||||
// address known at runtime. C++ compilers usually emit at least one of these
|
||||
// instructions for a call through a callable builtin variable.
|
||||
//
|
||||
// It is possible to use callable scalars as non-type template arguments. This
|
||||
// way the compiler knows which function we want to call when generating the
|
||||
// code for the call site, so it may inline (if it decides to do so) or use a
|
||||
// direct call instead of being forced to use a slow, indirect call.
|
||||
//
|
||||
// We define a functor class template that encodes the function to call in its
|
||||
// type via a non-type template argument. Its (inline declared) overloaded
|
||||
// function call operator calls the function through that non-type template
|
||||
// argument. In the best case we end up inlining the callee directly at the
|
||||
// point of the call.
|
||||
//
|
||||
// Decomposition of the wrapped member function's type is needed in order to
|
||||
// implement argument forwarding (just using a templated call operator we would
|
||||
// encounter what is known as "the forwarding problem" [Dimov1]). Further we
|
||||
// can eliminate unecessary copies for each by-value parameter by using a
|
||||
// reference to its const qualified type for the corresponding parameter of the
|
||||
// wrapper's function call operator.
|
||||
//
|
||||
// Finally we provide a macro that does have similar semantics to the function
|
||||
// template mem_fn of the Bind [2] library.
|
||||
// We can't use a function template and use a macro instead, because we use a
|
||||
// member function pointer that is a compile time constant. So we first have to
|
||||
// deduce the type and create a template that accepts this type as a non-type
|
||||
// template argument, which is passed in in a second step. The macro hides this
|
||||
// lengthy expression from the user.
|
||||
//
|
||||
//
|
||||
// Limitations
|
||||
// ===========
|
||||
//
|
||||
// The "this-argument" must be specified as a reference.
|
||||
//
|
||||
//
|
||||
// Bibliography
|
||||
// ============
|
||||
//
|
||||
// [Dimov1] Dimov, P., Hinnant H., Abrahams, D. The Forwarding Problem
|
||||
// http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
|
||||
//
|
||||
// [Dimov2] Dimov, P. Documentation of boost::mem_fn
|
||||
// http://www.boost.org/libs/bind/mem_fn.html
|
||||
|
||||
#ifndef BOOST_EXAMPLE_FAST_MEM_FN_HPP_INCLUDED
|
||||
#ifndef BOOST_PP_IS_ITERATING
|
||||
|
||||
|
||||
#include <boost/function_types/result_type.hpp>
|
||||
#include <boost/function_types/function_arity.hpp>
|
||||
#include <boost/function_types/parameter_types.hpp>
|
||||
#include <boost/function_types/is_member_function_pointer.hpp>
|
||||
|
||||
#include <boost/mpl/transform_view.hpp>
|
||||
#include <boost/mpl/begin.hpp>
|
||||
#include <boost/mpl/next.hpp>
|
||||
#include <boost/mpl/deref.hpp>
|
||||
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
#include "detail/param_type.hpp"
|
||||
|
||||
namespace example
|
||||
{
|
||||
|
||||
namespace ft = boost::function_types;
|
||||
namespace mpl = boost::mpl;
|
||||
using namespace mpl::placeholders;
|
||||
|
||||
// the functor class template
|
||||
template< typename MFPT, MFPT MemberFunction
|
||||
, size_t Arity = ::example::ft::function_arity<MFPT>::value
|
||||
>
|
||||
struct fast_mem_fn;
|
||||
|
||||
// ------- ---- --- -- - - - -
|
||||
|
||||
// deduce type and capture compile time value
|
||||
#define BOOST_EXAMPLE_FAST_MEM_FN(mfp) \
|
||||
::example::make_fast_mem_fn(mfp).make_fast_mem_fn<mfp>()
|
||||
|
||||
template<typename MFPT>
|
||||
struct fast_mem_fn_maker
|
||||
{
|
||||
template<MFPT Callee>
|
||||
fast_mem_fn<MFPT,Callee> make_fast_mem_fn()
|
||||
{
|
||||
return fast_mem_fn<MFPT,Callee>();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename MFPT>
|
||||
typename boost::enable_if<boost::is_member_function_pointer<MFPT>,
|
||||
fast_mem_fn_maker<MFPT> >::type
|
||||
make_fast_mem_fn(MFPT)
|
||||
{
|
||||
return fast_mem_fn_maker<MFPT>();
|
||||
}
|
||||
|
||||
|
||||
// ------- ---- --- -- - - - -
|
||||
|
||||
namespace detail
|
||||
{
|
||||
// by-value forwarding optimization
|
||||
template<typename T>
|
||||
struct parameter_types
|
||||
: mpl::transform_view<ft::parameter_types<T>,param_type<_> >
|
||||
{ };
|
||||
}
|
||||
|
||||
// ------- ---- --- -- - - - -
|
||||
|
||||
template< typename MFPT, MFPT MemberFunction >
|
||||
struct fast_mem_fn<MFPT, MemberFunction, 1>
|
||||
{
|
||||
// decompose the result and the parameter types (public for introspection)
|
||||
typedef typename ft::result_type<MFPT>::type result_type;
|
||||
typedef detail::parameter_types<MFPT> parameter_types;
|
||||
private:
|
||||
// iterate the parameter types
|
||||
typedef typename mpl::begin<parameter_types>::type i0;
|
||||
public:
|
||||
// forwarding function call operator
|
||||
result_type operator()( typename mpl::deref<i0>::type a0) const
|
||||
{
|
||||
return (a0.*MemberFunction)();
|
||||
};
|
||||
};
|
||||
|
||||
template< typename MFPT, MFPT MemberFunction >
|
||||
struct fast_mem_fn<MFPT, MemberFunction, 2>
|
||||
{
|
||||
// decompose the result and the parameter types (public for introspection)
|
||||
typedef typename ft::result_type<MFPT>::type result_type;
|
||||
typedef detail::parameter_types<MFPT> parameter_types;
|
||||
private:
|
||||
// iterate the parameter types
|
||||
typedef typename mpl::begin<parameter_types>::type i0;
|
||||
typedef typename mpl::next<i0>::type i1;
|
||||
public:
|
||||
// forwarding function call operator
|
||||
result_type operator()( typename mpl::deref<i0>::type a0
|
||||
, typename mpl::deref<i1>::type a1) const
|
||||
{
|
||||
return (a0.*MemberFunction)(a1);
|
||||
};
|
||||
};
|
||||
|
||||
template< typename MFPT, MFPT MemberFunction >
|
||||
struct fast_mem_fn<MFPT, MemberFunction, 3>
|
||||
{
|
||||
// decompose the result and the parameter types (public for introspection)
|
||||
typedef typename ft::result_type<MFPT>::type result_type;
|
||||
typedef detail::parameter_types<MFPT> parameter_types;
|
||||
private:
|
||||
// iterate the parameter types
|
||||
typedef typename mpl::begin<parameter_types>::type i0;
|
||||
typedef typename mpl::next<i0>::type i1;
|
||||
typedef typename mpl::next<i1>::type i2;
|
||||
public:
|
||||
// forwarding function call operator
|
||||
result_type operator()( typename mpl::deref<i0>::type a0
|
||||
, typename mpl::deref<i1>::type a1
|
||||
, typename mpl::deref<i2>::type a2) const
|
||||
{
|
||||
return (a0.*MemberFunction)(a1,a2);
|
||||
};
|
||||
};
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
// ------- ---- --- -- - - - -
|
||||
|
||||
// preprocessor-based code generator to continue the repetitive part, above
|
||||
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/arithmetic/inc.hpp>
|
||||
#include <boost/preprocessor/iteration/iterate.hpp>
|
||||
#include <boost/preprocessor/iteration/local.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_shifted_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||||
|
||||
namespace example
|
||||
{
|
||||
#if BOOST_FT_MAX_ARITY >= 4
|
||||
# define BOOST_PP_FILENAME_1 "fast_mem_fn.hpp"
|
||||
# define BOOST_PP_ITERATION_LIMITS (4,BOOST_FT_MAX_ARITY)
|
||||
# include BOOST_PP_ITERATE()
|
||||
#endif
|
||||
}
|
||||
|
||||
#define BOOST_EXAMPLE_FAST_MEM_FN_HPP_INCLUDED
|
||||
#else
|
||||
|
||||
#define N BOOST_PP_FRAME_ITERATION(1)
|
||||
template< typename MFPT, MFPT MemberFunction >
|
||||
struct fast_mem_fn<MFPT, MemberFunction, N >
|
||||
{
|
||||
// decompose the result and the parameter types (public for introspection)
|
||||
typedef typename ft::result_type<MFPT>::type result_type;
|
||||
typedef detail::parameter_types<MFPT> parameter_types;
|
||||
private:
|
||||
// iterate the parameter types
|
||||
typedef typename mpl::begin<parameter_types>::type i0;
|
||||
#define BOOST_PP_LOCAL_LIMITS (0,N-2)
|
||||
#define BOOST_PP_LOCAL_MACRO(j) \
|
||||
typedef typename mpl::next< i ## j >::type BOOST_PP_CAT(i,BOOST_PP_INC(j)) ;
|
||||
#include BOOST_PP_LOCAL_ITERATE()
|
||||
public:
|
||||
// forwarding function call operator
|
||||
result_type operator()(
|
||||
BOOST_PP_ENUM_BINARY_PARAMS(N, typename mpl::deref<i,>::type a) ) const
|
||||
{
|
||||
return (a0.*MemberFunction)(BOOST_PP_ENUM_SHIFTED_PARAMS(N,a));
|
||||
};
|
||||
};
|
||||
#undef N
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
118
example/fast_mem_fn_example.cpp
Normal file
118
example/fast_mem_fn_example.cpp
Normal file
@ -0,0 +1,118 @@
|
||||
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// See fast_mem_fn.hpp in this directory for details.
|
||||
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include <boost/timer.hpp>
|
||||
#include <boost/mem_fn.hpp>
|
||||
|
||||
#include "fast_mem_fn.hpp"
|
||||
|
||||
// test class that holds a single integer with getter function
|
||||
class test
|
||||
{
|
||||
int val_id;
|
||||
public:
|
||||
|
||||
explicit test(int id)
|
||||
: val_id(id)
|
||||
{ }
|
||||
|
||||
int id() const
|
||||
{ return val_id; }
|
||||
|
||||
};
|
||||
|
||||
// STL style comparator that applies the CriterionExtractor function to both
|
||||
// operands and compares the results with Comparator
|
||||
template<typename CriterionExtractor, typename Comparator>
|
||||
class test_compare
|
||||
{
|
||||
CriterionExtractor fnc_criterion;
|
||||
Comparator fnc_compare;
|
||||
public:
|
||||
|
||||
explicit test_compare(CriterionExtractor criterion, Comparator compare)
|
||||
: fnc_criterion(criterion)
|
||||
, fnc_compare(compare)
|
||||
{ }
|
||||
|
||||
template<typename T>
|
||||
inline bool operator()(T const & lhs, T const & rhs) const
|
||||
{
|
||||
return fnc_compare(fnc_criterion(lhs),fnc_criterion(rhs));
|
||||
}
|
||||
};
|
||||
|
||||
// helper function to construct an instance of the test_compare comparator.
|
||||
template<typename CriterionExtractor, typename Comparator>
|
||||
test_compare<CriterionExtractor,Comparator>
|
||||
make_test_compare(CriterionExtractor criterion, Comparator compare)
|
||||
{
|
||||
return test_compare<CriterionExtractor,Comparator>(criterion,compare);
|
||||
}
|
||||
|
||||
// the test case: sort N test objects by id
|
||||
//
|
||||
// the objects are in ascending order before the test run and in descending
|
||||
// order after it
|
||||
|
||||
static const unsigned N = 2000000;
|
||||
|
||||
typedef std::vector<test> test_vector;
|
||||
|
||||
|
||||
void setup_test(test_vector & v)
|
||||
{
|
||||
v.clear();
|
||||
v.reserve(N);
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
v.push_back(test(i));
|
||||
}
|
||||
|
||||
template<typename F> void do_test(test_vector & v, F criterion)
|
||||
{
|
||||
std::sort(v.begin(),v.end(),make_test_compare(criterion,std::greater<int>()));
|
||||
assert(v.begin()->id() == N-1);
|
||||
}
|
||||
|
||||
|
||||
// compare performance with boost::mem_fn
|
||||
int main()
|
||||
{
|
||||
test_vector v;
|
||||
boost::timer t;
|
||||
double time1, time2;
|
||||
|
||||
std::cout <<
|
||||
"Test case: sorting " << N << " objects.\n\n"
|
||||
"Criterion accessor called with | elasped seconds\n"
|
||||
"-------------------------------|----------------" << std::endl;
|
||||
|
||||
setup_test(v);
|
||||
t.restart();
|
||||
do_test(v, BOOST_EXAMPLE_FAST_MEM_FN(& test::id));
|
||||
time1 = t.elapsed();
|
||||
std::cout << "fast_mem_fn | " << time1 << std::endl;
|
||||
|
||||
setup_test(v);
|
||||
t.restart();
|
||||
do_test(v, boost::mem_fn(& test::id));
|
||||
time2 = t.elapsed();
|
||||
std::cout << "mem_fn | " << time2 << std::endl;
|
||||
|
||||
std::cout << '\n' << (time2/time1-1)*100 << "% speedup" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
361
example/interface.hpp
Normal file
361
example/interface.hpp
Normal file
@ -0,0 +1,361 @@
|
||||
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// This example implements interfaces.
|
||||
//
|
||||
// Detailed description
|
||||
// ====================
|
||||
//
|
||||
// An interface is a collection of member function prototypes that may be
|
||||
// implemented by classes. Objects of classes that implement the interface can
|
||||
// then be assigned to an interface variable through which the interface's
|
||||
// functions can be called.
|
||||
//
|
||||
// Interfaces are a feature of the Java programming language [Gosling] and the
|
||||
// most obvious way to model interfaces in C++ is (multiple) inheritance.
|
||||
// Using inheritance for this purpose, however, is neither the most efficient
|
||||
// nor the most flexible solution, because:
|
||||
//
|
||||
// - all functions must be virtual,
|
||||
//
|
||||
// => a function that calls another function of the interface must do so
|
||||
// via virtual dispatch (as opposed to inlining)
|
||||
// => a class can not implement an interface's (overloaded) function via
|
||||
// a function template
|
||||
//
|
||||
// - inhertitance is intrusive
|
||||
//
|
||||
// => object size increases
|
||||
// => client's are always polymorphic
|
||||
// => dependencies cause tighter coupling
|
||||
//
|
||||
// Fortunately it is possible to eliminate all the drawbacks mentioned above
|
||||
// based on an alternative implementation proposed by David Abrahams.
|
||||
// We'll add some detail to the original scheme (see [Abrahams]) such as
|
||||
// support for overloaded and const qualified functions.
|
||||
// The implementation in this example uses Boost.FunctionTypes to shift
|
||||
// metaprogramming code from the preprocessor into templates, to reduce
|
||||
// preprocessing time and increase maintainability.
|
||||
//
|
||||
//
|
||||
// Limitations
|
||||
// ===========
|
||||
//
|
||||
// There is no lifetime management as implemented by the Boost candidate
|
||||
// Interfaces library (see [Turkanis]).
|
||||
//
|
||||
// This example does not compile with Visual C++. Template argument deduction
|
||||
// from the result of the address-of operator does not work properly with this
|
||||
// compiler. It is possible to partially work around the problem, but it isn't
|
||||
// done here for the sake of readability.
|
||||
//
|
||||
//
|
||||
// Bibliography
|
||||
// ============
|
||||
//
|
||||
// [Gosling] Gosling, J., Joy, B., Steele, G. The Java Language Specification
|
||||
// http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html
|
||||
//
|
||||
// [Abrahams] Abrahams, D. Proposal: interfaces, Post to newsgroup comp.std.c++
|
||||
// http://groups.google.com/group/comp.std.c++/msg/85af30a61bf677e4
|
||||
//
|
||||
// [Turkanis] Turkanis, J., Diggins, C. Boost candidate Interfaces library
|
||||
// http://www.kangaroologic.com/interfaces/libs/interfaces/doc/index.html
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/function_types/function_pointer.hpp>
|
||||
#include <boost/function_types/member_function_pointer.hpp>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#include <boost/utility/addressof.hpp>
|
||||
|
||||
#include <boost/mpl/at.hpp>
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/mpl/joint_view.hpp>
|
||||
#include <boost/mpl/single_view.hpp>
|
||||
#include <boost/mpl/transform_view.hpp>
|
||||
|
||||
#include <boost/preprocessor/seq/seq.hpp>
|
||||
#include <boost/preprocessor/seq/enum.hpp>
|
||||
#include <boost/preprocessor/seq/elem.hpp>
|
||||
#include <boost/preprocessor/seq/size.hpp>
|
||||
#include <boost/preprocessor/tuple/elem.hpp>
|
||||
#include <boost/preprocessor/arithmetic/dec.hpp>
|
||||
#include <boost/preprocessor/arithmetic/inc.hpp>
|
||||
#include <boost/preprocessor/facilities/empty.hpp>
|
||||
#include <boost/preprocessor/facilities/identity.hpp>
|
||||
#include <boost/preprocessor/punctuation/comma_if.hpp>
|
||||
#include <boost/preprocessor/iteration/local.hpp>
|
||||
#include <boost/preprocessor/repetition/enum.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_trailing_params.hpp>
|
||||
|
||||
#include "detail/param_type.hpp"
|
||||
|
||||
namespace example
|
||||
{
|
||||
namespace ft = boost::function_types;
|
||||
namespace mpl = boost::mpl;
|
||||
using namespace mpl::placeholders;
|
||||
|
||||
// join a single type and an MPL-sequence
|
||||
// in some ways similar to mpl::push_front (but mpl::push_front requires
|
||||
// an MPL Extensible Sequence and this template does not)
|
||||
template<typename T, typename Seq>
|
||||
struct concat_view
|
||||
: mpl::joint_view<mpl::single_view<T>, Seq>
|
||||
{ };
|
||||
|
||||
// metafunction returning a function pointer type for a vtable entry
|
||||
template<typename Inf>
|
||||
struct vtable_entry
|
||||
: ft::function_pointer
|
||||
< concat_view< typename Inf::result, mpl::transform_view<
|
||||
typename Inf::params, param_type<_> > > >
|
||||
{ };
|
||||
|
||||
// the expression '& member<MetaInfo,Tag>::wrap<& Class::Function> ' in an
|
||||
// assignment context binds the member function Function of Class with the
|
||||
// properties described by MetaInfo and Tag to the corresponding vtable
|
||||
// entry
|
||||
template<typename Inf, typename Tag>
|
||||
struct member
|
||||
{
|
||||
typedef typename ft::member_function_pointer
|
||||
< concat_view<typename Inf::result,typename Inf::params>,Tag
|
||||
>::type
|
||||
mem_func_ptr;
|
||||
|
||||
typedef typename mpl::at_c<typename Inf::params,0>::type context;
|
||||
|
||||
template<mem_func_ptr MemFuncPtr>
|
||||
static typename Inf::result wrap(void* c)
|
||||
{
|
||||
return (reinterpret_cast<context*>(c)->*MemFuncPtr)();
|
||||
}
|
||||
template<mem_func_ptr MemFuncPtr, typename T0>
|
||||
static typename Inf::result wrap(void* c, T0 a0)
|
||||
{
|
||||
return (reinterpret_cast<context*>(c)->*MemFuncPtr)(a0);
|
||||
}
|
||||
template<mem_func_ptr MemFuncPtr, typename T0, typename T1>
|
||||
static typename Inf::result wrap(void* c, T0 a0, T1 a1)
|
||||
{
|
||||
return (reinterpret_cast<context*>(c)->*MemFuncPtr)(a0,a1);
|
||||
}
|
||||
// continue with the preprocessor (the scheme should be clear, by now)
|
||||
#define BOOST_PP_LOCAL_MACRO(n) \
|
||||
template<mem_func_ptr MemFuncPtr, BOOST_PP_ENUM_PARAMS(n,typename T)> \
|
||||
static typename Inf::result wrap(void* c, \
|
||||
BOOST_PP_ENUM_BINARY_PARAMS(n,T,a)) \
|
||||
{ \
|
||||
return (reinterpret_cast<context*>(c)->*MemFuncPtr)( \
|
||||
BOOST_PP_ENUM_PARAMS(n,a) ); \
|
||||
}
|
||||
#define BOOST_PP_LOCAL_LIMITS (3,BOOST_FT_MAX_ARITY-1)
|
||||
#include BOOST_PP_LOCAL_ITERATE()
|
||||
};
|
||||
|
||||
// extract a parameter by index
|
||||
template<typename Inf, std::size_t Index>
|
||||
struct param
|
||||
: param_type< typename mpl::at_c< typename Inf::params,Index>::type >
|
||||
{ };
|
||||
}
|
||||
|
||||
// the interface definition on the client's side
|
||||
#define BOOST_EXAMPLE_INTERFACE(name,def) \
|
||||
class name \
|
||||
{ \
|
||||
struct vtable \
|
||||
{ \
|
||||
BOOST_EXAMPLE_INTERFACE__MEMBERS(def,VTABLE) \
|
||||
}; \
|
||||
\
|
||||
vtable const * ptr_vtable; \
|
||||
void * ptr_that; \
|
||||
\
|
||||
template<class T> struct vtable_holder \
|
||||
{ \
|
||||
static vtable const val_vtable; \
|
||||
}; \
|
||||
\
|
||||
public: \
|
||||
\
|
||||
template<class T> \
|
||||
inline name (T & that) \
|
||||
: ptr_vtable(& vtable_holder<T>::val_vtable) \
|
||||
, ptr_that(boost::addressof(that)) \
|
||||
{ } \
|
||||
\
|
||||
BOOST_EXAMPLE_INTERFACE__MEMBERS(def,FUNCTION) \
|
||||
}; \
|
||||
\
|
||||
template<typename T> \
|
||||
name ::vtable const name ::vtable_holder<T>::val_vtable \
|
||||
= { BOOST_EXAMPLE_INTERFACE__MEMBERS(def,INIT_VTABLE) }
|
||||
|
||||
|
||||
#ifdef BOOST_PP_NIL // never defined -- a comment with syntax highlighting
|
||||
|
||||
BOOST_EXAMPLE_INTERFACE( interface_x,
|
||||
(( a_func, (void)(int), const_qualified ))
|
||||
(( another_func, (int), non_const ))
|
||||
);
|
||||
|
||||
// expands to:
|
||||
class interface_x
|
||||
{
|
||||
struct vtable
|
||||
{
|
||||
// meta information for first function
|
||||
template<typename T = void*> struct inf0
|
||||
{
|
||||
typedef void result;
|
||||
typedef ::boost::mpl::vector< T, int > params;
|
||||
};
|
||||
// function pointer with void* context pointer and parameters optimized
|
||||
// for forwarding
|
||||
::example::vtable_entry<inf0<> >::type func0;
|
||||
|
||||
// second function
|
||||
template<typename T = void*> struct inf1
|
||||
{
|
||||
typedef int result;
|
||||
typedef ::boost::mpl::vector< T > params;
|
||||
};
|
||||
::example::vtable_entry<inf1<> >::type func1;
|
||||
};
|
||||
|
||||
// data members
|
||||
vtable const * ptr_vtable;
|
||||
void * ptr_that;
|
||||
|
||||
// this template is instantiated for every class T this interface is created
|
||||
// from, causing the compiler to emit an initialized vtable for this type
|
||||
// (see aggregate assignment, below)
|
||||
template<class T> struct vtable_holder
|
||||
{
|
||||
static vtable const val_vtable;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
// converting ctor, creates an interface from an arbitrary class
|
||||
template<class T>
|
||||
inline interface_x (T & that)
|
||||
: ptr_vtable(& vtable_holder<T>::val_vtable)
|
||||
, ptr_that(boost::addressof(that))
|
||||
{ }
|
||||
|
||||
// the member functions from the interface definition, parameters are
|
||||
// optimized for forwarding
|
||||
|
||||
inline vtable::inf0<> ::result a_func (
|
||||
::example::param<vtable::inf0<>,1>::type p0) const
|
||||
{
|
||||
return ptr_vtable-> func0(ptr_that , p0);
|
||||
}
|
||||
|
||||
inline vtable::inf1<> ::result another_func ()
|
||||
{
|
||||
return ptr_vtable-> func1(ptr_that );
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
interface_x ::vtable const interface_x ::vtable_holder<T>::val_vtable =
|
||||
{
|
||||
// instantiate function templates that wrap member function pointers (which
|
||||
// are known at compile time) by taking their addresses in assignment to
|
||||
// function pointer context
|
||||
& ::example::member< vtable::inf0<T>, ::example::ft:: const_qualified >
|
||||
::template wrap < &T:: a_func >
|
||||
, & ::example::member< vtable::inf1<T>, ::example::ft:: non_const >
|
||||
::template wrap < &T:: another_func >
|
||||
};
|
||||
#endif
|
||||
|
||||
// preprocessing code details
|
||||
|
||||
// iterate all of the interface's members and invoke a macro (prefixed with
|
||||
// BOOST_EXAMPLE_INTERFACE_)
|
||||
#define BOOST_EXAMPLE_INTERFACE__MEMBERS(seq,macro) \
|
||||
BOOST_PP_REPEAT(BOOST_PP_SEQ_SIZE(seq), \
|
||||
BOOST_EXAMPLE_INTERFACE__ ## macro,seq)
|
||||
|
||||
// extract signature sequence from entry
|
||||
#define BOOST_EXAMPLE_INTERFACE__VTABLE(z,i,seq) \
|
||||
BOOST_EXAMPLE_INTERFACE__VTABLE_I(z,i, \
|
||||
BOOST_PP_TUPLE_ELEM(3,1,BOOST_PP_SEQ_ELEM(i,seq)))
|
||||
|
||||
// split the signature sequence result/params and insert T at the beginning of
|
||||
// the params part
|
||||
#define BOOST_EXAMPLE_INTERFACE__VTABLE_I(z,i,seq) \
|
||||
BOOST_EXAMPLE_INTERFACE__VTABLE_II(z,i, \
|
||||
BOOST_PP_SEQ_HEAD(seq),(T)BOOST_PP_SEQ_TAIL(seq))
|
||||
|
||||
// emit the meta information structure and function pointer declaration
|
||||
#define BOOST_EXAMPLE_INTERFACE__VTABLE_II(z,i,result_type,param_types) \
|
||||
template<typename T = void*> \
|
||||
struct BOOST_PP_CAT(inf,i) \
|
||||
{ \
|
||||
typedef result_type result; \
|
||||
typedef ::boost::mpl::vector< BOOST_PP_SEQ_ENUM(param_types) > params; \
|
||||
}; \
|
||||
::example::vtable_entry<BOOST_PP_CAT(inf,i)<> >::type BOOST_PP_CAT(func,i);
|
||||
|
||||
// extract tuple entry from sequence and precalculate the name of the function
|
||||
// pointer variable
|
||||
#define BOOST_EXAMPLE_INTERFACE__INIT_VTABLE(z,i,seq) \
|
||||
BOOST_EXAMPLE_INTERFACE__INIT_VTABLE_I(i,seq,BOOST_PP_CAT(func,i), \
|
||||
BOOST_PP_SEQ_ELEM(i,seq))
|
||||
|
||||
// emit a function pointer expression that encapsulates the corresponding
|
||||
// member function of T
|
||||
#define BOOST_EXAMPLE_INTERFACE__INIT_VTABLE_I(i,seq,func,desc) \
|
||||
BOOST_PP_COMMA_IF(i) & ::example::member< BOOST_PP_CAT(vtable::inf,i)<T>, \
|
||||
::example::ft:: BOOST_PP_TUPLE_ELEM(3,2,desc) >::template wrap \
|
||||
< &T:: BOOST_PP_TUPLE_ELEM(3,0,desc) >
|
||||
|
||||
// extract tuple entry from sequence
|
||||
#define BOOST_EXAMPLE_INTERFACE__FUNCTION(z,i,seq) \
|
||||
BOOST_EXAMPLE_INTERFACE__FUNCTION_I(z,i,BOOST_PP_SEQ_ELEM(i,seq))
|
||||
|
||||
// precalculate function name, arity, name of meta info structure and cv-
|
||||
// qualifiers
|
||||
#define BOOST_EXAMPLE_INTERFACE__FUNCTION_I(z,i,desc) \
|
||||
BOOST_EXAMPLE_INTERFACE__FUNCTION_II(z,i, \
|
||||
BOOST_PP_TUPLE_ELEM(3,0,desc), \
|
||||
BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(BOOST_PP_TUPLE_ELEM(3,1,desc))), \
|
||||
BOOST_PP_CAT(vtable::inf,i)<>, \
|
||||
BOOST_PP_CAT(BOOST_EXAMPLE_INTERFACE___,BOOST_PP_TUPLE_ELEM(3,2,desc)) \
|
||||
)
|
||||
|
||||
// emit the definition for a member function of the interface
|
||||
#define BOOST_EXAMPLE_INTERFACE__FUNCTION_II(z,i,name,arity,types,cv) \
|
||||
inline types ::result name \
|
||||
(BOOST_PP_ENUM_ ## z (arity,BOOST_EXAMPLE_INTERFACE__PARAM,types)) cv() \
|
||||
{ \
|
||||
return ptr_vtable-> BOOST_PP_CAT(func,i)(ptr_that \
|
||||
BOOST_PP_ENUM_TRAILING_PARAMS_Z(z,arity,p)); \
|
||||
}
|
||||
|
||||
// emit a parameter of the function definition
|
||||
#define BOOST_EXAMPLE_INTERFACE__PARAM(z,j,types) \
|
||||
::example::param<types,BOOST_PP_INC(j)>::type BOOST_PP_CAT(p,j)
|
||||
|
||||
// helper macros to map 'const_qualified' to 'const' an 'non_const' to ''
|
||||
#define BOOST_EXAMPLE_INTERFACE___const_qualified BOOST_PP_IDENTITY(const)
|
||||
#define BOOST_EXAMPLE_INTERFACE___non_const BOOST_PP_EMPTY
|
||||
|
||||
|
79
example/interface_example.cpp
Normal file
79
example/interface_example.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// See interface.hpp in this directory for details.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "interface.hpp"
|
||||
|
||||
|
||||
BOOST_EXAMPLE_INTERFACE( interface_x,
|
||||
(( a_func, (void)(int) , const_qualified ))
|
||||
(( a_func, (void)(long), const_qualified ))
|
||||
(( another_func, (int) , non_const ))
|
||||
);
|
||||
|
||||
|
||||
// two classes that implement interface_x
|
||||
|
||||
struct a_class
|
||||
{
|
||||
void a_func(int v) const
|
||||
{
|
||||
std::cout << "a_class::void a_func(int v = " << v << ")" << std::endl;
|
||||
}
|
||||
|
||||
void a_func(long v) const
|
||||
{
|
||||
std::cout << "a_class::void a_func(long v = " << v << ")" << std::endl;
|
||||
}
|
||||
|
||||
int another_func()
|
||||
{
|
||||
std::cout << "a_class::another_func() = 3" << std::endl;
|
||||
return 3;
|
||||
}
|
||||
};
|
||||
|
||||
struct another_class
|
||||
{
|
||||
// note: overloaded a_func implemented as a function template
|
||||
template<typename T>
|
||||
void a_func(T v) const
|
||||
{
|
||||
std::cout <<
|
||||
"another_class::void a_func(T v = " << v << ")"
|
||||
" [ T = " << typeid(T).name() << " ]" << std::endl;
|
||||
}
|
||||
|
||||
int another_func()
|
||||
{
|
||||
std::cout << "another_class::another_func() = 5" << std::endl;
|
||||
return 5;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// both classes above can be assigned to the interface variable and their
|
||||
// member functions can be called through it
|
||||
int main()
|
||||
{
|
||||
a_class x;
|
||||
another_class y;
|
||||
|
||||
interface_x i(x);
|
||||
i.a_func(12);
|
||||
i.a_func(77L);
|
||||
i.another_func();
|
||||
|
||||
i = y;
|
||||
i.a_func(13);
|
||||
i.a_func(21L);
|
||||
i.another_func();
|
||||
}
|
||||
|
188
example/interpreter.hpp
Normal file
188
example/interpreter.hpp
Normal file
@ -0,0 +1,188 @@
|
||||
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// This example implements a simple batch-style interpreter that is capable of
|
||||
// calling functions previously registered with it. The parameter types of the
|
||||
// functions are used to control the parsing of the input.
|
||||
//
|
||||
// Implementation description
|
||||
// ==========================
|
||||
//
|
||||
// When a function is registered, an 'invoker' template is instantiated with
|
||||
// the function's type. The 'invoker' fetches a value from the 'token_parser'
|
||||
// for each parameter of the function into a tuple and finally invokes the the
|
||||
// function with these values as arguments. The invoker's entrypoint, which
|
||||
// is a function of the callable builtin that describes the function to call and
|
||||
// a reference to the 'token_parser', is partially bound to the registered
|
||||
// function and put into a map so it can be found by name during parsing.
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/token_iterator.hpp>
|
||||
#include <boost/token_functions.hpp>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
|
||||
#include <boost/fusion/algorithm/transformation/push_back.hpp>
|
||||
#include <boost/fusion/sequence/container/list/cons.hpp>
|
||||
#include <boost/fusion/functional/invocation/invoke.hpp>
|
||||
|
||||
#include <boost/mpl/begin.hpp>
|
||||
#include <boost/mpl/end.hpp>
|
||||
#include <boost/mpl/next.hpp>
|
||||
#include <boost/mpl/deref.hpp>
|
||||
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
|
||||
#include <boost/function_types/is_nonmember_callable_builtin.hpp>
|
||||
#include <boost/function_types/parameter_types.hpp>
|
||||
|
||||
namespace example
|
||||
{
|
||||
namespace fusion = boost::fusion;
|
||||
namespace ft = boost::function_types;
|
||||
namespace mpl = boost::mpl;
|
||||
|
||||
class interpreter
|
||||
{
|
||||
class token_parser;
|
||||
typedef boost::function<void(token_parser &)> invoker_function;
|
||||
typedef std::map<std::string, invoker_function> dictionary;
|
||||
|
||||
dictionary map_invokers;
|
||||
public:
|
||||
// Registers a function with the interpreter.
|
||||
template<typename Function>
|
||||
typename boost::enable_if< ft::is_nonmember_callable_builtin<Function>
|
||||
>::type register_function(std::string const & name, Function f);
|
||||
|
||||
// Parse input for functions to call.
|
||||
void parse_input(std::string const & text) const;
|
||||
|
||||
private:
|
||||
template< typename Function
|
||||
, class From = typename mpl::begin< ft::parameter_types<Function> >::type
|
||||
, class To = typename mpl::end< ft::parameter_types<Function> >::type
|
||||
>
|
||||
struct invoker;
|
||||
};
|
||||
|
||||
class interpreter::token_parser
|
||||
{
|
||||
typedef boost::token_iterator_generator<
|
||||
boost::char_separator<char> >::type token_iterator;
|
||||
|
||||
token_iterator itr_at, itr_to;
|
||||
public:
|
||||
|
||||
token_parser(token_iterator from, token_iterator to)
|
||||
: itr_at(from), itr_to(to)
|
||||
{ }
|
||||
|
||||
private:
|
||||
template<typename T>
|
||||
struct remove_cv_ref
|
||||
: boost::remove_cv< typename boost::remove_reference<T>::type >
|
||||
{ };
|
||||
public:
|
||||
// Returns a token of given type.
|
||||
// We just apply boost::lexical_cast to whitespace separated string tokens
|
||||
// for simplicity.
|
||||
template<typename RequestedType>
|
||||
typename remove_cv_ref<RequestedType>::type get()
|
||||
{
|
||||
if (! this->has_more_tokens())
|
||||
throw std::runtime_error("unexpected end of input");
|
||||
|
||||
try
|
||||
{
|
||||
typedef typename remove_cv_ref<RequestedType>::type result_type;
|
||||
result_type result = boost::lexical_cast
|
||||
<typename remove_cv_ref<result_type>::type>(*this->itr_at);
|
||||
++this->itr_at;
|
||||
return result;
|
||||
}
|
||||
|
||||
catch (boost::bad_lexical_cast &)
|
||||
{ throw std::runtime_error("invalid argument: " + *this->itr_at); }
|
||||
}
|
||||
|
||||
// Any more tokens?
|
||||
bool has_more_tokens() const { return this->itr_at != this->itr_to; }
|
||||
};
|
||||
|
||||
template<typename Function, class From, class To>
|
||||
struct interpreter::invoker
|
||||
{
|
||||
// add an argument to a Fusion cons-list for each parameter type
|
||||
template<typename Args>
|
||||
static inline
|
||||
void apply(Function func, token_parser & parser, Args const & args)
|
||||
{
|
||||
typedef typename mpl::deref<From>::type arg_type;
|
||||
|
||||
invoker<Function, typename mpl::next<From>::type, To>::apply
|
||||
( func, parser, fusion::push_back(args, parser.get<arg_type>()) );
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function, class To>
|
||||
struct interpreter::invoker<Function,To,To>
|
||||
{
|
||||
// the argument list is complete, now call the function
|
||||
template<typename Args>
|
||||
static inline
|
||||
void apply(Function func, token_parser &, Args const & args)
|
||||
{
|
||||
fusion::invoke(func,args);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Function>
|
||||
typename boost::enable_if< ft::is_nonmember_callable_builtin<Function> >::type
|
||||
interpreter::register_function(std::string const & name, Function f)
|
||||
{
|
||||
// instantiate and store the invoker by name
|
||||
this->map_invokers[name] = boost::bind(
|
||||
& invoker<Function>::template apply<fusion::nil>, f,_1,fusion::nil() );
|
||||
}
|
||||
|
||||
|
||||
void interpreter::parse_input(std::string const & text) const
|
||||
{
|
||||
boost::char_separator<char> s(" \t\n\r");
|
||||
|
||||
token_parser parser
|
||||
( boost::make_token_iterator<std::string>(text.begin(), text.end(), s)
|
||||
, boost::make_token_iterator<std::string>(text.end() , text.end(), s) );
|
||||
|
||||
while (parser.has_more_tokens())
|
||||
{
|
||||
// read function name
|
||||
std::string func_name = parser.get<std::string>();
|
||||
|
||||
// look up function
|
||||
dictionary::const_iterator entry = map_invokers.find( func_name );
|
||||
if (entry == map_invokers.end())
|
||||
throw std::runtime_error("unknown function: " + func_name);
|
||||
|
||||
// call the invoker which controls argument parsing
|
||||
entry->second(parser);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
56
example/interpreter_example.cpp
Normal file
56
example/interpreter_example.cpp
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "interpreter.hpp"
|
||||
|
||||
void echo(std::string const & s)
|
||||
{
|
||||
std::cout << s << std::endl;
|
||||
}
|
||||
|
||||
void add(int a, int b)
|
||||
{
|
||||
std::cout << a + b << std::endl;
|
||||
}
|
||||
|
||||
void repeat(std::string const & s, int n)
|
||||
{
|
||||
while (--n >= 0) std::cout << s;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
example::interpreter interpreter;
|
||||
|
||||
interpreter.register_function("echo", & echo);
|
||||
interpreter.register_function("add", & add);
|
||||
interpreter.register_function("repeat", & repeat);
|
||||
|
||||
std::string line = "nonempty";
|
||||
while (! line.empty())
|
||||
{
|
||||
std::cout << std::endl << "] ", std::getline(std::cin,line);
|
||||
|
||||
try
|
||||
{
|
||||
interpreter.parse_input(line);
|
||||
}
|
||||
catch (std::runtime_error &error)
|
||||
{
|
||||
std::cerr << error.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
73
example/macro_type_args.hpp
Normal file
73
example/macro_type_args.hpp
Normal file
@ -0,0 +1,73 @@
|
||||
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// This example implements a utility to accept a type expression, that may
|
||||
// contain commas to a macro.
|
||||
//
|
||||
//
|
||||
// Detailed description
|
||||
// ====================
|
||||
//
|
||||
// Accepting a type as macro argument can cause problems if the type expression
|
||||
// contains commas:
|
||||
//
|
||||
// #define MY_MACRO(a_type)
|
||||
// ...
|
||||
// MY_MACRO(std::map<int,int>) // ERROR (wrong number of macro arguments)
|
||||
//
|
||||
// This problem can be solved by pasing using a parenthesized type
|
||||
//
|
||||
// MY_MACRO((std::map<int,int>) // OK
|
||||
//
|
||||
// but then there is no way to remove the parentheses in the macro argument
|
||||
// with the preprocessor.
|
||||
// We can, however, form a pointer to a function with a single argument (the
|
||||
// parentheses become part of the type) and extract the argument with template
|
||||
// metaprogramming:
|
||||
//
|
||||
// // Inside the macro definition
|
||||
//
|
||||
// typename mpl::front< parameter_types<void(*)a_type> >::type
|
||||
//
|
||||
// This code snippet does not read too expressive so we use another macro
|
||||
// to encapsulate the solution:
|
||||
//
|
||||
// // Inside the macro definition
|
||||
//
|
||||
// BOOST_EXAMPLE_MACRO_TYPE_ARGUMENT(a_type)
|
||||
//
|
||||
// As a generalization of this technique we can accept a comma-separated list of
|
||||
// types. Omitting the mpl::front invocation gives us an MPL-sequence.
|
||||
//
|
||||
//
|
||||
// Limitations
|
||||
// ===========
|
||||
//
|
||||
// - only works for types that are valid function arguments
|
||||
//
|
||||
// Acknowledgments
|
||||
// ===============
|
||||
//
|
||||
// Thanks go to Dave Abrahams for letting me know this technique.
|
||||
|
||||
#ifndef BOOST_EXAMPLE_MACRO_TYPE_ARGUMENT_HPP_INCLUDED
|
||||
#define BOOST_EXAMPLE_MACRO_TYPE_ARGUMENT_HPP_INCLUDED
|
||||
|
||||
#include <boost/function_types/parameter_types.hpp>
|
||||
#include <boost/mpl/front.hpp>
|
||||
|
||||
#define BOOST_EXAMPLE_MACRO_TYPE_ARGUMENT(parenthesized_type) \
|
||||
boost::mpl::front< \
|
||||
BOOST_EXAMPLE_MACRO_TYPE_LIST_ARGUMENT(parenthesized_type) >::type
|
||||
|
||||
#define BOOST_EXAMPLE_MACRO_TYPE_LIST_ARGUMENT(parenthesized_types) \
|
||||
::boost::function_types::parameter_types< void(*) parenthesized_types >
|
||||
|
||||
|
||||
#endif
|
||||
|
71
example/macro_type_args_example.cpp
Normal file
71
example/macro_type_args_example.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// See macro_type_arugment.hpp in this directory for details.
|
||||
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/mpl/begin_end.hpp>
|
||||
#include <boost/mpl/deref.hpp>
|
||||
|
||||
#include "macro_type_args.hpp"
|
||||
|
||||
|
||||
#define TYPE_NAME(parenthesized_type) \
|
||||
typeid(BOOST_EXAMPLE_MACRO_TYPE_ARGUMENT(parenthesized_type)).name()
|
||||
|
||||
namespace example
|
||||
{
|
||||
namespace mpl = boost::mpl;
|
||||
|
||||
template<class Curr, class End>
|
||||
struct mpl_seq_to_string_impl
|
||||
{
|
||||
static std::string get(std::string const & prev)
|
||||
{
|
||||
typedef typename mpl::next<Curr>::type next_pos;
|
||||
typedef typename mpl::deref<Curr>::type type;
|
||||
|
||||
return mpl_seq_to_string_impl<next_pos,End>::get(
|
||||
prev + (prev.empty()? '\0' : ',') + typeid(type).name() );
|
||||
}
|
||||
};
|
||||
template<class End>
|
||||
struct mpl_seq_to_string_impl<End, End>
|
||||
{
|
||||
static std::string get(std::string const & prev)
|
||||
{
|
||||
return prev;
|
||||
}
|
||||
};
|
||||
|
||||
template<class Seq>
|
||||
std::string mpl_seq_to_string()
|
||||
{
|
||||
typedef typename mpl::begin<Seq>::type begin;
|
||||
typedef typename mpl::end<Seq>::type end;
|
||||
|
||||
return mpl_seq_to_string_impl<begin, end>::get("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define TYPE_NAMES(parenthesized_types) \
|
||||
::example::mpl_seq_to_string< \
|
||||
BOOST_EXAMPLE_MACRO_TYPE_LIST_ARGUMENT(parenthesized_types) >()
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << TYPE_NAME((int)) << std::endl;
|
||||
|
||||
std::cout << TYPE_NAMES((int,char)) << std::endl;
|
||||
std::cout << TYPE_NAMES((int,char,long)) << std::endl;
|
||||
|
||||
}
|
||||
|
86
example/result_of.hpp
Normal file
86
example/result_of.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Reimplementation of the Boost result_of utility (see [Gregor01] and
|
||||
// [Gregor02]).
|
||||
//
|
||||
//
|
||||
// Detailed description
|
||||
// ====================
|
||||
//
|
||||
// This example implements the functionality of the Boost result_of utility.
|
||||
// Because of FunctionTypes we get away without repetitive code and the Boost
|
||||
// Preprocessor library.
|
||||
//
|
||||
//
|
||||
// Bibliography
|
||||
// ============
|
||||
//
|
||||
// [Gregor01] Gregor, D. The Boost result_of utility
|
||||
// http://www.boost.org/libs/utility
|
||||
//
|
||||
// [Gregor02] Gregor, D. A uniform method for computing function object return
|
||||
// types (revision 1)
|
||||
// http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1454.html
|
||||
|
||||
#include <boost/function_types/result_type.hpp>
|
||||
#include <boost/function_types/is_callable_builtin.hpp>
|
||||
|
||||
#include <boost/mpl/eval_if.hpp>
|
||||
#include <boost/mpl/has_xxx.hpp>
|
||||
|
||||
namespace example
|
||||
{
|
||||
namespace ft = boost::function_types;
|
||||
namespace mpl = boost::mpl;
|
||||
|
||||
template<typename F> struct result_of;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
BOOST_MPL_HAS_XXX_TRAIT_DEF(result_type)
|
||||
|
||||
template<typename F>
|
||||
struct result_type_member
|
||||
{
|
||||
typedef typename F::result_type type;
|
||||
};
|
||||
|
||||
template<typename F, typename Desc>
|
||||
struct result_member_template
|
||||
{
|
||||
typedef typename F::template result<Desc>::type type;
|
||||
};
|
||||
|
||||
#if !BOOST_WORKAROUND(__BORLANDC__,BOOST_TESTED_AT(0x564))
|
||||
template<typename F>
|
||||
struct result_member_template< F, F(void) >
|
||||
{
|
||||
typedef void type;
|
||||
};
|
||||
#endif
|
||||
|
||||
template<typename F, typename Desc>
|
||||
struct result_of_impl
|
||||
: mpl::eval_if
|
||||
< ft::is_callable_builtin<F>
|
||||
, ft::result_type<F>
|
||||
, mpl::eval_if
|
||||
< has_result_type<F>
|
||||
, result_type_member<F>
|
||||
, result_member_template<F,Desc>
|
||||
> >
|
||||
{ };
|
||||
}
|
||||
|
||||
template<typename Desc>
|
||||
struct result_of
|
||||
: detail::result_of_impl< typename ft::result_type<Desc>::type, Desc >
|
||||
{ };
|
||||
}
|
||||
|
59
example/result_of_example.cpp
Normal file
59
example/result_of_example.cpp
Normal file
@ -0,0 +1,59 @@
|
||||
|
||||
// (C) Copyright Douglas Gregor 2003-2004.
|
||||
// (C) Copyright Tobias Schwinger
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software License,
|
||||
// Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// This file is a modified copy of the original Boost.ResultOf test-suite.
|
||||
// See result_of.hpp in this directory for details.
|
||||
|
||||
|
||||
#include "result_of.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
|
||||
struct int_result_type { typedef int result_type; };
|
||||
|
||||
struct int_result_of
|
||||
{
|
||||
template<typename F> struct result { typedef int type; };
|
||||
};
|
||||
|
||||
struct int_result_type_and_float_result_of
|
||||
{
|
||||
typedef int result_type;
|
||||
template<typename F> struct result { typedef float type; };
|
||||
};
|
||||
|
||||
struct X {};
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
namespace e = example;
|
||||
|
||||
typedef int (*func_ptr)(float, double);
|
||||
typedef int (&func_ref)(float, double);
|
||||
typedef int (X::*mem_func_ptr)(float);
|
||||
typedef int (X::*mem_func_ptr_c)(float) const;
|
||||
typedef int (X::*mem_func_ptr_v)(float) volatile;
|
||||
typedef int (X::*mem_func_ptr_cv)(float) const volatile;
|
||||
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<int_result_type(float)>::type, int>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<int_result_of(double)>::type, int>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<int_result_of(void)>::type, void>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<const int_result_of(double)>::type, int>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<volatile int_result_of(void)>::type, void>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<int_result_type_and_float_result_of(char)>::type, int>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<func_ptr(char, float)>::type, int>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<func_ref(char, float)>::type, int>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<mem_func_ptr(X,char)>::type, int>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<mem_func_ptr_c(X,char)>::type, int>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<mem_func_ptr_v(X,char)>::type, int>::value));
|
||||
BOOST_STATIC_ASSERT((is_same<e::result_of<mem_func_ptr_cv(X,char)>::type, int>::value));
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user