Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to write make_unique() in VS2012?

Herb Sutter propose a simple implementation of make_unique() there: http://herbsutter.com/gotw/_102/

Here it is:

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

My problem is that variadic templates are not yet part of VS2012, so I can't use this code as is.

Is there a maintainable way to write this in VS2012 that wouldn't involve copy-pasting the same function with different args count?

like image 935
Klaim Avatar asked Sep 22 '12 21:09

Klaim


3 Answers

You could use Boost.Preprocessor to generate the different parameter counts, but I really don't see the advantage of that. Simply do the grunt job once, stuff it in a header and be done. You're saving yourself compile time and have your make_unique.

Here's a copy-paste of my make_unique.h header that simulates variadic templates for up to 5 arguments.


Since OP seems to not like copy-paste work, here's the Boost.Preprocessor code to generate the above:

First, make a main header that includes the template header multiple times (Boost.Preprocessor iteration code blatantly stolen from this answer):

// 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

And now make a template header that gets included again and again and expands differently depending on the value of 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
like image 192
Xeo Avatar answered Oct 06 '22 01:10

Xeo


Even though variadic templates are not part of VS2012, there are macros built into the header file <memory> that help simulate them.

See this very nice answer which shows how to implement make_unique<T> in just a few cryptic lines. I confirmed that it works well:

#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
like image 35
Hugues Avatar answered Oct 06 '22 00:10

Hugues


The only way to simulate functions with variadic argument lists is by creating a suitable list of overloads. Whether this is done manually, using something like the Boost preprocessor library, or using a suitable generator all amounts to the same: real variadic argument lists cannot be simulated. Personally, I think the most maintainable version of simulating variadic argument lists is to use a compiler which supports them as preprocessor and have it generate code suitable to be compiled by compilers not, yet, up to support variadic templates.

like image 40
Dietmar Kühl Avatar answered Oct 06 '22 01:10

Dietmar Kühl