Want feedback on C++ version of Python's explode operator

Discussion in 'C++' started by k04jg02@gmail.com, Feb 6, 2007.

  1. Guest

    Python has a nifty operator that will take a container and pass its
    elements as function parameters. In Python you can make a list like
    so:

    x = [1, 2, 3]

    Then you can say:

    f(*x)

    Which is the same as f(x[0], x[1], x[2]). I thought it would be nice
    to have the same functionality for C++. I've written an implementation
    of it, that lets you write things like this:

    int sum(int x, int y) { return x + y; }

    boost::array<int, 2> operands = { 3, 4 };
    boost::function<int(int, int)> Sum = sum;
    explode(Sum, operands); // Same as writing sum(operands[0],
    operands[1])

    It makes heavy use of template and boost preprocessor magic, but it
    seems to work. I'm looking for feedback on how to improve it (it looks
    rather obfuscated). I'm still new to heavy template usage and so their
    might be better ways to accomplish this. Right now it's limited to
    working on containers that are of a type with a static_size member
    defining their size (like boost::array has), but should be easily
    expandable to working on builtin arrays, specified ranges, etc.

    I've divided it up into three files:
    1. bind_append.hpp -- Defines a wrapper around boost::bind that
    assumes you want to bind a parameter to the end of the parameter list
    and leave the rest of the parameters alone in normal order.
    2. remove_arg.hpp -- A function trait that gives you the same function
    type with one parameter removed.
    3. explode.hpp -- implementation of explode()

    // ===========bind_append.hpp=================
    /*
    Author: Joseph Garvin (2006)

    bindappend is a wrapper around boost::bind that assumes you want to
    append
    1 argument to the current function object, immediately to the end of
    the
    argument list, and want to leave placeholders, in order, for the
    rest. It's
    less flexible than bind but combined with remove_arg is useful for
    iteratively
    applying parameters to a function. Example:

    int sum(int x, int y, int z) { return x + y + z; }

    bindappend(sum, 3) // Equivalent to bind(sum, 3, _1, 2)
    */

    #ifndef BOOST_PP_IS_ITERATING

    #ifndef INCLUDED_BIND_APPEND_H
    #define INCLUDED_BIND_APPEND_H

    #include <boost/preprocessor/repetition.hpp>
    #include <boost/static_assert.hpp>
    #include <boost/preprocessor/iteration/iterate.hpp>
    #include <boost/bind.hpp>
    #include <boost/function.hpp>
    #include <boost/type_traits/function_traits.hpp>
    #include <meta/remove_arg.hpp>

    using namespace boost;

    template<class FuncType, class ParamType, int remainingArity>
    struct bindappend_impl
    {
    // Error! We have no remaining arity!
    BOOST_STATIC_ASSERT ( sizeof ( ParamType ) == 0 );
    };

    #ifndef BIND_APPEND_MAX_SIZE
    #define BIND_APPEND_MAX_SIZE 8
    #endif

    #define BOOST_PP_ITERATION_LIMITS (0, BIND_APPEND_MAX_SIZE)
    #define BOOST_PP_FILENAME_1 <bind_append.hpp>
    #include BOOST_PP_ITERATE()

    template<class FuncType, class ParamType>
    function<typename remove_arg<FuncType>::type>
    bind_append(function<FuncType> func, ParamType param)
    {
    return bindappend_impl<FuncType, ParamType,
    function_traits<FuncType>::arity - 1>::bind_append(func, param);
    }

    #endif // INCLUDED_BIND_APPEND_H

    #else // BOOST_PP_IS_ITERATING

    #define n BOOST_PP_ITERATION()

    template<class FuncType, class ParamType>
    struct bindappend_impl <FuncType, ParamType, n>
    {
    static function<typename remove_arg<FuncType>::type>
    bind_append(function<FuncType> func, ParamType param);
    };

    template<class FuncType, class ParamType>
    function<typename remove_arg<FuncType>::type>
    bindappend_impl<FuncType, ParamType,
    n>::bind_append(function<FuncType> func, ParamType param)
    {
    return bind(func, param BOOST_PP_COMMA_IF (n)
    BOOST_PP_ENUM_SHIFTED_PARAMS (BOOST_PP_ADD(n, 1), _) );
    }

    #undef n

    #endif // BOOST_PP_IS_ITERATING


    // ===========remove_arg.hpp=================
    /*
    Author: Joseph Garvin (2006)

    remove_arg is a compile time function that takes a function type and
    returns
    the same function type with one less argument. E.g. it transforms:

    int(char, float, double)

    To:

    int(float, double)

    Example Usage:

    boost::function<remove_arg<FuncType> > foo = boost::bind_append(foo,
    x);
    */

    #ifndef BOOST_PP_IS_ITERATING

    #ifndef INCLUDED_REMOVE_ARG_H
    #define INCLUDED_REMOVE_ARG_H

    #include <boost/preprocessor/repetition.hpp>
    #include <boost/static_assert.hpp>
    #include <boost/preprocessor/iteration/iterate.hpp>

    template<typename R>
    struct remove_arg
    {
    // Error! We have no parameters to strip!
    BOOST_STATIC_ASSERT ( sizeof ( R ) == 0 );
    };

    #ifndef REMOVE_ARG_MAX_SIZE
    #define REMOVE_ARG_MAX_SIZE 8
    #endif

    #define BOOST_PP_ITERATION_LIMITS (1, REMOVE_ARG_MAX_SIZE)
    #define BOOST_PP_FILENAME_1 <remove_arg.hpp>
    #include BOOST_PP_ITERATE()

    #endif // INCLUDED_REMOVE_ARG_H

    #else // BOOST_PP_IS_ITERATING

    #define n BOOST_PP_ITERATION()

    template <class R BOOST_PP_COMMA_IF ( n ) BOOST_PP_ENUM_PARAMS ( n,
    class T ) >
    struct remove_arg <R ( BOOST_PP_ENUM_PARAMS ( n,T ) ) >
    {
    typedef R type ( BOOST_PP_ENUM_SHIFTED_PARAMS (n, T ) );
    };

    #undef n

    #endif // BOOST_PP_IS_ITERATING


    // ===========explode.hpp=================
    #include <boost/function.hpp>
    #include <boost/type_traits/function_traits.hpp>
    #include <boost/bind.hpp>
    #include <boost/static_assert.hpp>

    #include <meta/remove_arg.hpp>
    #include <meta/bind_append.hpp>

    template<class FuncSig, class FixedSizeSTLContainer, int arity>
    class Explode_Helper
    {
    public:
    static typename function_traits<FuncSig>::result_type
    explode_helper(function<FuncSig> func, FixedSizeSTLContainer args);
    };

    template<class FuncSig, class FixedSizeSTLContainer, int arity>
    typename function_traits<FuncSig>::result_type
    Explode_Helper<FuncSig, FixedSizeSTLContainer,
    arity>::explode_helper(function<FuncSig> func, FixedSizeSTLContainer
    args)
    {
    function<typename remove_arg<FuncSig>::type > appliedFunc =
    bind_append(func, args[FixedSizeSTLContainer::static_size - arity]);
    return Explode_Helper<
    typename remove_arg<FuncSig>::type,
    FixedSizeSTLContainer,
    function_traits<typename remove_arg<FuncSig>::type>::arity
    >
    ::
    explode_helper(appliedFunc, args);
    }

    template<class FuncSig, class FixedSizeSTLContainer>
    class Explode_Helper<FuncSig, FixedSizeSTLContainer, 0>
    {
    public:
    static typename function_traits<FuncSig>::result_type
    explode_helper(function<FuncSig> func, FixedSizeSTLContainer args);
    };

    template<class FuncSig, class FixedSizeSTLContainer>
    typename function_traits<FuncSig>::result_type
    Explode_Helper<FuncSig, FixedSizeSTLContainer,
    0>::explode_helper(function<FuncSig> func, FixedSizeSTLContainer args)
    {
    return func();
    }

    template<class FuncSig, class FixedSizeSTLContainer>
    typename function_traits<FuncSig>::result_type
    explode(function<FuncSig> func, FixedSizeSTLContainer args)
    {
    BOOST_STATIC_ASSERT ( function_traits<FuncSig>::arity ==
    FixedSizeSTLContainer::static_size );

    return Explode_Helper<FuncSig, FixedSizeSTLContainer,
    function_traits<FuncSig>::arity>::explode_helper(func, args);
    }
     
    , Feb 6, 2007
    #1
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. JKop

    BEFORE I EXPLODE

    JKop, Sep 18, 2004, in forum: C++
    Replies:
    17
    Views:
    895
    Old Wolf
    Sep 20, 2004
  2. AceHigh

    Pelles C POLIB.EXE /EXPLODE utility

    AceHigh, Sep 23, 2005, in forum: C Programming
    Replies:
    3
    Views:
    813
    jacob navia
    Sep 25, 2005
  3. cc
    Replies:
    0
    Views:
    315
  4. V Green
    Replies:
    0
    Views:
    865
    V Green
    Feb 5, 2008
  5. PA Bear [MS MVP]
    Replies:
    0
    Views:
    975
    PA Bear [MS MVP]
    Feb 5, 2008
Loading...

Share This Page