Google Groups Home
Help | Sign in
Want feedback on C++ version of Python's explode operator
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  1 message - Expand all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
k04j...@gmail.com  
View profile  
 More options Feb 6 2007, 11:35 am
Newsgroups: comp.lang.c++
From: k04j...@gmail.com
Date: 6 Feb 2007 08:35:45 -0800
Local: Tues, Feb 6 2007 11:35 am
Subject: Want feedback on C++ version of Python's explode operator
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);


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2009 Google