Using Boost.Preprocessor to reduce this code repitition

吃可爱长大的小学妹 提交于 2019-12-01 06:09:24

问题


Consider the following code:

template<typename T0>
void send( const std::string& func, const T0& t0 )
{
   std::ostringstream s;
   s << func << ": " << t0;
   sendMessage( s.str() );
}

template<typename T0, typename T1>
void send( const std::string& func, const T0& t0, const T1& t1 )
{
   std::ostringstream s;
   s << func << ": " << t0 << "," << t1;
   sendMessage( s.str() );
}

template<typename T0, typename T1, typename T2>
void send( const std::string& func, const T0& t0, const T1& t1, const T2& t2 )
{
   std::ostringstream s;
   s << func << ": " << t0 << "," << t1 << "," << t2;
   sendMessage( s.str() );
}

etc...

I need this up to something like 15 arguments.

I'm just wondering if it's possible to use Boost.Preprocessor to simplify this repetition, and how I would go about it. I looked through the docs but it's fairly confusing.


回答1:


boost.preprocessor can do this kind of stuff and you can have descent tutorial here: Intro to preprocessor metaprogramming

For your specific example here's the code I came up with (note: I just ran it under the preprocessor to check that the resulting code was what I would expect but did not try to compile the code itself).

This uses both the enum_params macro that helps generate list of attributes and local_iterate that allow to expand a macro with a range of argument. I have also a macro if to handle your special case with ": " vs "," for the first argument sent to your stream.

Overall when you start to understand how boost.preprocessor work searching for the feature you need in its reference manual becomes relatively easy and its a "reasonable" replacement until variadic templates are supported by most compilers. Do note though that it is very intensive at compilation time, so use with caution.

edit: While I did consider this as a general exercise with a relatively simple example I do agree though that in term of coding for this specific example using a pseudo stream class as suggested by synek317 would be a more flexible and "lightweight" solution. Again implementing such stream do not require you to do the specialization of all the operators and in fact boost again provide the IOStreams library to help you implement a class as a standard C++ stream (http://www.boost.org/doc/libs/1_52_0/libs/iostreams/doc/index.html)

#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/control/if.hpp>

# ifndef MY_SEND_MAX
#  define MY_SEND_MAX 15
# endif

/*
 * macros called through BOOST_PP_REPEAT to generate lists
 * J : I don't know what it is
 * I : the current counter number
 * D : the 3rd argument of BOOST_PP_REPEAT
 */
// Generate the list of arguments after std::string
# define MY_SEND_PARAM(J,I,D) , BOOST_PP_CAT(const T,I) & BOOST_PP_CAT(arg,I)
// Generate the stream's <<s adter the string
# define MY_SEND_STREAM(J,I,D) <<BOOST_PP_IF(I,",",": ")<<BOOST_PP_CAT(arg,I)

/*
 * Macro to call for generating onde function
 * N : the number of arguments
 */
// Create one function with a string and N extra aarguments
# define MY_SEND(N) \           
  template<BOOST_PP_ENUM_PARAMS(N,typename T)>  \
  void send(std::string const &fn BOOST_PP_REPEAT(N,MY_SEND_PARAM,~)) { \
    std::ostringstream s; \
    s<<fn BOOST_PP_REPEAT(N,MY_SEND_STREAM,~); \
    sendMessage(s.str()); \
  }
// End of my macro

/*
 * BOOST_PP local loop to generate all the the function
 */
// What macro to call in the loop
#define BOOST_PP_LOCAL_MACRO(n)   MY_SEND(n)
// do the job form 0 to MY_SEND_MAX 
#define BOOST_PP_LOCAL_LIMITS     (0,MY_SEND_MAX)
// execute the loop
#include BOOST_PP_LOCAL_ITERATE()

// undefine all my stuff
# undef MY_SEND_PARAM
# undef MY_SEND_STREAM
# undef MY_SEND
# undef BOOST_PP_LOCAL_MACRO
# undef BOOST_PP_LOCAL_LIMITS



回答2:


15 arguments sounds like really bad idea. Maybe you can create an object which will behave like stream? In your example, you can easily inherit from ostringstream and add method send() and I belive similar problems can be solved this way, maybe with operator<< overload.

Preprocessor is nice, but way to often hard to debug.



来源:https://stackoverflow.com/questions/12188227/using-boost-preprocessor-to-reduce-this-code-repitition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!