16

Herb Sutter は、make_unique()そこの簡単な実装を提案しています: http://herbsutter.com/gotw/_102/

ここにあります:

template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
    return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}

私の問題は、可変個引数テンプレートがまだ VS2012 の一部ではないため、このコードをそのまま使用できないことです。

VS2012 でこれを記述し、同じ関数を異なる引数カウントでコピー アンド ペーストする必要のない保守可能な方法はありますか?

4

6 に答える 6

14

Boost.Preprocessorを使用してさまざまなパラメーター数を生成することもできますが、その利点は実際にはわかりません。ただ一度うなり声の仕事をして、それをヘッダーに詰めて、完了してください。コンパイル時間を節約し、を使用できますmake_unique

make_unique.hこれは、最大5つの引数の可変個引数テンプレートをシミュレートするヘッダーコピーペーストです。


OPはコピーと貼り付けの作業を好まないようですので、上記を生成するBoost.Preprocessorコードを次に示します。

まず、テンプレートヘッダーを複数回含むメインヘッダーを作成します(この回答から露骨に盗まれたBoost.Preprocessor反復コード):

// make_unique.h
#include <memory>
#include <utility>
#include <boost/preprocessor.hpp>

#ifndef MAKE_UNIQUE_NUM_ARGS
// allow this to be changed to a higher number if needed,
// ten is a good default number
#define MAKE_UNIQUE_NUM_ARGS 10
#endif

#if MAKE_UNIQUE_NUM_ARGS < 0
// but don't be stupid with it
#error Invalid MAKE_UNIQUE_NUM_ARGS value.
#endif

/* optional, see above for premade version
// include premade functions, to avoid the costly iteration
#include "detail/blah_premade.hpp

// generate classes if needed
#if MAKE_UNIQUE_NUM_ARGS > MAKE_UNIQUE_NUM_PREMADE
*/
#define BOOST_PP_ITERATION_LIMITS (0, MAKE_UNIQUE_NUM_ARGS)
#define BOOST_PP_FILENAME_1 "make_unique_template.h"
#include BOOST_PP_ITERATE()
//#endif

そして今度は、何度も何度も含まれ、次の値に応じて異なる方法で展開されるテンプレートヘッダーを作成しますMAKE_UNIQUE_NUM_ARGS

// make_unique_template.h
// note: no include guard

#define N BOOST_PP_ITERATION()    

#define MAKE_UNIQUE_TEMPLATE_PARMS \
  BOOST_PP_ENUM_PARAMS(N, typename A)

#define MAKE_UNIQUE_FUNCTION_PARM(J,I,D) \
  BOOST_PP_CAT(A,I)&& BOOST_PP_CAT(a,I)

#define MAKE_UNIQUE_FUNCTION_PARMS \
  BOOST_PP_ENUM(N, MAKE_UNIQUE_FUNCTION_PARM, BOOST_PP_EMPTY)

#define MAKE_UNIQUE_ARG(J,I,D) \
  std::forward<BOOST_PP_CAT(A,I)>(BOOST_PP_CAT(a,I))

#define MAKE_UNIQUE_ARGS \
  BOOST_PP_ENUM(N, MAKE_UNIQUE_ARG, BOOST_PP_EMPTY)

template<class T BOOST_PP_COMMA_IF(N) MAKE_UNIQUE_TEMPLATE_PARMS>
std::unique_ptr<T> make_unique(MAKE_UNIQUE_FUNCTION_PARMS){
  return std::unique_ptr<T>(new T(MAKE_UNIQUE_ARGS));
}

// clean up
#undef MAKE_UNIQUE_TEMPLATE_PARMS
#undef MAKE_UNIQUE_FUNCTION_PARM
#undef MAKE_UNIQUE_FUNCTION_PARMS
#undef MAKE_UNIQUE_ARG
#undef MAKE_UNIQUE_ARGS
#undef N
于 2012-09-22T22:00:10.540 に答える
8

可変個引数テンプレートはVS2012の一部ではありませんが、<memory>それらをシミュレートするのに役立つマクロがヘッダーファイルに組み込まれています。

ほんの数行の不可解な行で実装する方法を示すこの非常に素晴らしい答えを参照してください。make_unique<T>私はそれがうまくいくことを確認しました:

#include <memory> // brings in TEMPLATE macros.
#define MAKE_UNIQUE(TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4)   \
  template<class T COMMA LIST(_CLASS_TYPE)>  \
  inline std::unique_ptr<T> make_unique(LIST(_TYPE_REFREF_ARG))  \
  {  \
      return std::unique_ptr<T>(new T(LIST(_FORWARD_ARG)));  \
  }
_VARIADIC_EXPAND_0X(MAKE_UNIQUE, , , , )
#undef MAKE_UNIQUE
于 2013-01-31T05:38:06.247 に答える
1

可変引数リストを持つ関数をシミュレートする唯一の方法は、オーバーロードの適切なリストを作成することです。Boost プリプロセッサ ライブラリのようなものを使用して手動で行うか、適切なジェネレータを使用して行うかにかかわらず、実際の可変引数リストはシミュレートできません。個人的には、可変引数リストをシミュレートする最も維持しやすいバージョンは、それらをプリプロセッサとしてサポートするコンパイラを使用し、可変引数リストをまだサポートしていないコンパイラでコンパイルするのに適したコードを生成させることだと思います。

于 2012-09-22T22:58:32.337 に答える
1

Huguesの回答を拡張して、配列をラップする一意のポインターの作成を処理し(基本的に、このペーパーのコードとマージしました)、VC2012プロジェクトで正常に機能する次のものを取得しました。

#include <memory>

template<class T> struct _Unique_if {
    typedef std::unique_ptr<T> _Single_object;
};

template<class T> struct _Unique_if<T[]> {
    typedef std::unique_ptr<T[]> _Unknown_bound;
};

template<class T, size_t N> struct _Unique_if<T[N]> {
    typedef void _Known_bound;
};

// Visual Studio 2012 - specific
#define _MAKE_UNIQUE(TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4)                                          \
template<class T COMMA LIST(_CLASS_TYPE)> inline typename _Unique_if<T>::_Single_object make_unique(LIST(_TYPE_REFREF_ARG))  \
{                                                                                                                            \
    return std::unique_ptr<T>(new T(LIST(_FORWARD_ARG)));                                                                    \
}
_VARIADIC_EXPAND_0X(_MAKE_UNIQUE, , , , )
#undef _MAKE_UNIQUE

template<class T> inline typename _Unique_if<T>::_Unknown_bound make_unique(size_t n) 
{
    typedef typename std::remove_extent<T>::type U;
    return std::unique_ptr<T>(new U[n]());
}

// Visual Studio 2012 - specific
#define _MAKE_UNIQUE(TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4)                                          \
template<class T COMMA LIST(_CLASS_TYPE)> typename _Unique_if<T>::_Known_bound make_unique(LIST(_TYPE_REFREF_ARG)) = delete;
_VARIADIC_EXPAND_0X(_MAKE_UNIQUE, , , , )
#undef _MAKE_UNIQUE
于 2013-09-23T18:53:20.493 に答える
0

ここでのパーティーに遅れていることはわかっていますが、これに出くわしました。私はこれをワンライナーマクロで行っています(VS2012と互換性があります):

#define MAKE_UNIQUE(T, ...) std::unique_ptr<T>(new T(__VA_ARGS__))

または移植性が低くなりますが、空のパラメーターを渡すことができます

#define MAKE_UNIQUE(T, ...) std::unique_ptr<T>(new T(##__VA_ARGS__))

次のように使用します。

// MAKE_UNIQUE takes the type followed by the arguments list ...
std::unique_ptr<MyClass> pPointer = MAKE_UNIQUE(MyClass, param_1, param_2, ..., param_n);
于 2018-03-07T16:11:21.773 に答える