3

次のコードを検討してください。

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() );
}

等...

私はこれを15個の引数のようなものまで必要とします。

Boost.Preprocessor を使用してこの繰り返しを単純化できるかどうか、またどのようにそれを行うかを考えています。ドキュメントを見ましたが、かなり混乱しています。

4

2 に答える 2

5

boost.preprocessorこの種のことを行うことができ、ここで降下チュートリアルを行うことができます:プリプロセッサメタプログラミングの概要

あなたの特定の例として、私が思いついたコードがあります(注:プリプロセッサーの下で実行して、結果のコードが期待どおりであることを確認しましたが、コード自体をコンパイルしようとしませんでした)。

これはenum_params、属性のリストを生成するのに役立つlocal_iterateマクロと、引数の範囲でマクロを展開できるマクロの両方を使用します。ストリームに送信される最初の引数に対して、「:」と「」を使用して特殊なケースを処理する場合のマクロもあります。

全体として、リファレンスマニュアルboost.preprocessorで必要な機能を検索する作業が比較的簡単になり、ほとんどのコンパイラで可変個引数テンプレートがサポートされるまでは「合理的な」置き換えになることを理解し始めると、ただし、コンパイル時には非常に集中的に使用されるため、注意して使用してください。

編集:私はこれを比較的単純な例での一般的な演習と見なしましたが、synek317によって提案された疑似ストリームクラスを使用したこの特定の例のコーディングに関しては、より柔軟で「軽量」なソリューションになることに同意します。このようなストリームを実装する場合でも、すべての演算子を特殊化する必要はありません。実際、ブーストは、クラスを標準のC ++ストリームとして実装するのに役立つIOStreamsライブラリを提供します(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
于 2013-01-29T23:50:02.790 に答える
1

15個の引数は本当に悪い考えのように聞こえます。ストリームのように動作するオブジェクトを作成できますか? あなたの例では、ostringstream から簡単に継承し、メソッド send() を追加できます。おそらく operator<< オーバーロードを使用して、同様の問題をこの方法で解決できると思います。

プリプロセッサは優れていますが、デバッグが難しいことがよくあります。

于 2012-08-30T01:38:42.207 に答える