472,806 Members | 1,797 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,806 software developers and data experts.

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, 2operands = { 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<FuncTypefunc, 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<FuncTypefunc, ParamType param);
};

template<class FuncType, class ParamType>
function<typename remove_arg<FuncType>::type>
bindappend_impl<FuncType, ParamType,
n>::bind_append(function<FuncTypefunc, 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<FuncSigfunc, FixedSizeSTLContainer args);
};

template<class FuncSig, class FixedSizeSTLContainer, int arity>
typename function_traits<FuncSig>::result_type
Explode_Helper<FuncSig, FixedSizeSTLContainer,
arity>::explode_helper(function<FuncSigfunc, 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<FuncSigfunc, FixedSizeSTLContainer args);
};

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

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

return Explode_Helper<FuncSig, FixedSizeSTLContainer,
function_traits<FuncSig>::arity>::explode_helper(f unc, args);
}

Feb 6 '07 #1
0 1890

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
by: Robert Brewer | last post by:
WARNING: The following is NOT all Pythonic. However, it is Python. This is just fun--nothing I'm going to put into production. I don't have any questions or problems--just thought I'd share. ...
4
by: Dan Perl | last post by:
pyfmf is a project I started a few months ago and that is registered with sourceforge (http://pyfmf.sourceforge.net, http://sourceforge.net/projects/pyfmf). It consists of a framework for file...
9
by: christopher diggins | last post by:
I would like some feedback if the follow code is standard compliant, and are there any obvious redundancies or inefficiencies? The purpose of the code is to emulate the behaviour of a struct FuBar...
17
by: JKop | last post by:
G++ gives the most un-informative, cryptic, BULLSHIT errors statements. I'm writing a program at the moment and I have to finish it real soon. The problem I'm having is illustrated in the...
5
by: David Coppit | last post by:
Hi all, Most smart pointers remove the need to call delete. What I want is a pointer that turns delete into a no-op for "unauthorized" clients. The reason is that I'm generating code from...
10
by: mwt | last post by:
This code works fine to download files from the web and write them to the local drive: import urllib f = urllib.urlopen("http://www.python.org/blah/blah.zip") g = f.read() file =...
17
by: Ron Adam | last post by:
I put together the following module today and would like some feedback on any obvious problems. Or even opinions of weather or not it is a good approach. While collating is not a difficult thing...
0
by: Tor Erik Soenvisen | last post by:
Hi, all I would like some feedback on a multithreaded HTTP server I've written. The server serves python-scripts by dynamically loading scripts in the same directory as itself. When a request is...
15
by: skip | last post by:
If you're an Emacs user who has used both python-mode.el (the python mode code distributed with Python and XEmacs) and python.el (the python mode code distributed with GNU Emacs), I'd like to get...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 2 August 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
0
linyimin
by: linyimin | last post by:
Spring Startup Analyzer generates an interactive Spring application startup report that lets you understand what contributes to the application startup time and helps to optimize it. Support for...
0
by: erikbower65 | last post by:
Here's a concise step-by-step guide for manually installing IntelliJ IDEA: 1. Download: Visit the official JetBrains website and download the IntelliJ IDEA Community or Ultimate edition based on...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Sept 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
14
DJRhino1175
by: DJRhino1175 | last post by:
When I run this code I get an error, its Run-time error# 424 Object required...This is my first attempt at doing something like this. I test the entire code and it worked until I added this - If...
0
by: Rina0 | last post by:
I am looking for a Python code to find the longest common subsequence of two strings. I found this blog post that describes the length of longest common subsequence problem and provides a solution in...
5
by: DJRhino | last post by:
Private Sub CboDrawingID_BeforeUpdate(Cancel As Integer) If = 310029923 Or 310030138 Or 310030152 Or 310030346 Or 310030348 Or _ 310030356 Or 310030359 Or 310030362 Or...
0
by: lllomh | last post by:
How does React native implement an English player?
0
by: Mushico | last post by:
How to calculate date of retirement from date of birth

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.