【问题标题】:Is there a way to write make_unique() in VS2012?有没有办法在 VS2012 中编写 make_unique() ?
【发布时间】:2012-09-14 21:45:21
【问题描述】:

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 中编写此代码,而不涉及复制粘贴具有不同 args 计数的相同函数?

【问题讨论】:

    标签: c++ templates c++11 variadic-templates unique-ptr


    【解决方案1】:

    我知道我在这里参加聚会迟到了,但我只是偶然发现了这个。我一直在使用单行宏(并且与 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);
    

    【讨论】:

      【解决方案2】:

      出于好奇,我试图做类似的事情 - 我需要支持比 4 个更多的参数 - 对于 _VARIADIC_EXPAND_0X 类型的解决方案 - 可能只支持 4 个。

      这是 MacroArg.h 头文件:

      #pragma once
      
      //
      // Retrieve the type
      //
      //  ARGTYPE( (ArgType) argName )                         => ArgType
      //
      // https://stackoverflow.com/questions/41453/how-can-i-add-reflection-to-a-c-application
      //
      #define ARGTYPE(x) ARGTYPE_PASS2(ARGTYPE_PASS1 x,)
      //
      //      => ARGTYPE_PASS2(ARGTYPE_PASS1 (ArgType) argName,)
      //
      #define ARGTYPE_PASS1(...) (__VA_ARGS__),
      //
      //      => ARGTYPE_PASS2( (ArgType), argName,)
      //
      #define ARGTYPE_PASS2(...) ARGTYPE_PASS3((__VA_ARGS__))
      //
      //      => ARGTYPE_PASS2(( (ArgType), argName,))
      //
      #define ARGTYPE_PASS3(x)   ARGTYPE_PASS4 x
      //
      //      => ARGTYPE_PASS4 ( (ArgType), argName,)
      //
      #define ARGTYPE_PASS4(x, ...) REM x
      //
      //      => REM (ArgType)
      //
      #define REM(...) __VA_ARGS__
      //
      //      => ArgType
      //
      
      //
      // This counts the number of args: (0 is also supported)
      //
      //
      //  NARGS( (ArgType1) argName1, (ArgType2) argName2 )   => 2
      //
      #define NARGS(...) NARGS_PASS2(NARGS_PASS1(__VA_ARGS__))
      //
      //  => NARGS_PASS2(NARGS_PASS1( (ArgType1) argName1, (ArgType2) argName2 ) )
      //
      #define NARGS_PASS1(...) unused, __VA_ARGS__
      //
      //  => NARGS_PASS2( unused, (ArgType1) argName1, (ArgType2) argName2 )
      //
      #define NARGS_PASS2(...) NARGS_PASS4(NARGS_PASS3(__VA_ARGS__, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
      //
      //  => NARGS_PASS4(NARGS_PASS3( unused, (ArgType1) argName1, (ArgType2) argName2 ) , 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0) )
      //
      #define NARGS_PASS3(_unused,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,VAL, ...) VAL
      //
      //  => NARGS_PASS4(2)
      //
      #define NARGS_PASS4(x) x
      //
      //  => 2
      //
      
      
      //
      // Show the type without parenthesis
      //
      //  ARGPAIR( (ArgType1) argName1 )                         => ArgType1 argName1
      //
      #define ARGPAIR(x) REM x
      //
      //  => REM (ArgType1) argName1
      //
      //  => ArgType1 argName1
      //
      
      //
      // Show the type without parenthesis
      //
      //  ARGPAIR( (ArgType1) argName1 )                         => ArgType1 && argName1
      //
      #define REFARGPAIR(x) REFREM x
      //
      //  => REFREM (ArgType1) argName1
      
      #define REFREM(...) __VA_ARGS__ &&
      //
      //  => ArgType1 && argName1
      //
      
      //
      // Strip off the type
      //
      //  ARGNAME( (ArgType1) argName1 )                      => argName1
      //
      #define ARGNAME(x) EAT x
      //
      //      => EAT (ArgType1) argName1
      //
      #define EAT(...)
      //
      //      => argName1
      //
      
      //
      // This will call a macro on each argument passed in
      //
      //  DOFOREACH(typename ARGTYPE, (ArgType1) argName1, (ArgType1) argName2 )
      //
      #define DOFOREACH(macro, ...) DOFOREACH_PASS1(CAT(DOFOREACH_, NARGS(__VA_ARGS__)), (macro, __VA_ARGS__))
      //
      //          => DOFOREACH_PASS1(CAT(DOFOREACH_, NARGS( (ArgType1) argName1, (ArgType1) argName2 ) ), (typename ARGTYPE, (ArgType1) argName1, (ArgType1) argName2 ) ))
      //          => DOFOREACH_PASS1(CAT(DOFOREACH_, 2), (typename ARGTYPE, (ArgType1) argName1, (ArgType1) argName2 ) ))
      //
      #define CAT(x, y) CAT_PASS1((x, y))
      //
      //          => DOFOREACH_PASS1(CAT_PASS1((DOFOREACH_, 2)), (typename ARGTYPE, (ArgType1) argName1, (ArgType1) argName2 ) ))
      //
      #define CAT_PASS1(x) PRIMITIVE_CAT x
      //
      //          => DOFOREACH_PASS1(PRIMITIVE_CAT (DOFOREACH_, 2), (typename ARGTYPE, (ArgType1) argName1, (ArgType1) argName2 ) ))
      //
      #define PRIMITIVE_CAT(x, y) x ## y
      //
      //          => DOFOREACH_PASS1( DOFOREACH_2 ), (typename ARGTYPE, (ArgType1) argName1, (ArgType1) argName2 ) ))
      //
      #define DOFOREACH_PASS1(m, x) m x
      //
      //          => DOFOREACH_2 (typename ARGTYPE, (ArgType1) argName1, (ArgType1) argName2 ) )
      //
      #define DOFOREACH_0(m)
      #define DOFOREACH_1(m, x1) m(x1)
      #define DOFOREACH_2(m, x1, x2) m(x1), m(x2)
      //
      //          => typename ARGTYPE( (ArgType1) argName1 ), typename ARGTYPE( (ArgType1) argName2 ) )
      //          => typename ArgType1, typename ArgType1
      //
      #define DOFOREACH_3(m, x1, x2, x3) m(x1), m(x2), m(x3)
      #define DOFOREACH_4(m, x1, x2, x3, x4) m(x1), m(x2), m(x3), m(x4)
      #define DOFOREACH_5(m, x1, x2, x3, x4, x5) m(x1), m(x2), m(x3), m(x4), m(x5)
      #define DOFOREACH_6(m, x1, x2, x3, x4, x5, x6) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6)
      #define DOFOREACH_7(m, x1, x2, x3, x4, x5, x6, x7) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7)
      #define DOFOREACH_8(m, x1, x2, x3, x4, x5, x6, x7, x8) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8)
      #define DOFOREACH_9(m, x1, x2, x3, x4, x5, x6, x7, x8, x9) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9)
      #define DOFOREACH_10(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10)
      #define DOFOREACH_11(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11)
      #define DOFOREACH_12(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12)
      #define DOFOREACH_13(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12), m(x13)
      #define DOFOREACH_14(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12), m(x13), m(x14)
      #define DOFOREACH_15(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12), m(x13), m(x14), m(x15)
      
      
      //
      //  Same version as DOFOREACH, except this one meant to be used for appending list of arguments. If 0 arguments, then list is not appended, otherwise additional command is added in front.
      //
      #define DOFOREACH2(macro, ...) DOFOREACH_PASS1(CAT(DOFOREACH2_, NARGS(__VA_ARGS__)), (macro, __VA_ARGS__))
      
      #define DOFOREACH2_0(m)
      #define DOFOREACH2_1(m, x1) ,m(x1)
      #define DOFOREACH2_2(m, x1, x2) ,m(x1), m(x2)
      #define DOFOREACH2_3(m, x1, x2, x3) ,m(x1), m(x2), m(x3)
      #define DOFOREACH2_4(m, x1, x2, x3, x4) ,m(x1), m(x2), m(x3), m(x4)
      #define DOFOREACH2_5(m, x1, x2, x3, x4, x5) ,m(x1), m(x2), m(x3), m(x4), m(x5)
      #define DOFOREACH2_6(m, x1, x2, x3, x4, x5, x6) ,m(x1), m(x2), m(x3), m(x4), m(x5), m(x6)
      #define DOFOREACH2_7(m, x1, x2, x3, x4, x5, x6, x7) ,m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7)
      #define DOFOREACH2_8(m, x1, x2, x3, x4, x5, x6, x7, x8) ,m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8)
      #define DOFOREACH2_9(m, x1, x2, x3, x4, x5, x6, x7, x8, x9) ,m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9)
      #define DOFOREACH2_10(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10) ,m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10)
      #define DOFOREACH2_11(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11) ,m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11)
      #define DOFOREACH2_12(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12) ,m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12)
      #define DOFOREACH2_13(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13) ,m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12), m(x13)
      #define DOFOREACH2_14(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14) ,m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12), m(x13), m(x14)
      #define DOFOREACH2_15(m, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) ,m(x1), m(x2), m(x3), m(x4), m(x5), m(x6), m(x7), m(x8), m(x9), m(x10), m(x11), m(x12), m(x13), m(x14), m(x15)
      
      //
      //  ARGX(1)     =>      (Arg1) arg1
      //
      #define ARGX(index) (Arg##index) arg##index
      
      //
      //  Defines same function with different amount of arguments.
      //
      #define DEFINE_MULTIARG_FUNC(macro) \
          macro ( ARGX(1) ); \
          macro ( ARGX(1), ARGX(2) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12), ARGX(13)  ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12), ARGX(13), ARGX(14)  ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12), ARGX(13), ARGX(14), ARGX(15)  ); \
      
      
      //
      //  Same as previous, except add support also of function with no arguments.
      //  (template functions normally requires at least one template parameter (so you write template<> in front of function and won't get error), that's why separate define)
      //
      #define DEFINE_MULTIARG_FUNC2(macro) \
          macro ( ); \
          macro ( ARGX(1) ); \
          macro ( ARGX(1), ARGX(2) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12) ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12), ARGX(13)  ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12), ARGX(13), ARGX(14)  ); \
          macro ( ARGX(1), ARGX(2), ARGX(3), ARGX(4), ARGX(5), ARGX(6), ARGX(7), ARGX(8), ARGX(9), ARGX(10), ARGX(11), ARGX(12), ARGX(13), ARGX(14), ARGX(15)  ); \
      
      /*
          Here is simple example of usage of these macros:
      
          #define MKFUNC_make_unique(...) \
          template <class T  DOFOREACH2(typename ARGTYPE, __VA_ARGS__) > \
          std::unique_ptr<T> make_unique(  DOFOREACH(REFARGPAIR, __VA_ARGS__) ) \
          { \
              return std::unique_ptr<T>( new T( DOFOREACH(ARGNAME, __VA_ARGS__) ) ); \
          }
      
          DEFINE_MULTIARG_FUNC2(MKFUNC_make_unique);      //<--
          #undef MKFUNC_make_unique
      
          Debugger will stall in "<--" this line, so it makes sense to keep amount of line absolute minimal.
      */
      

      可以在此处找到有关调试宏的一些详细信息(正在讨论类似的问题)

      How can I add reflection to a C++ application?

      【讨论】:

        【解决方案3】:

        我已经扩展了 Hugues 的答案以处理创建包装数组的唯一指针(基本上将其与 this paper 中的代码合并)并获得了以下内容,这在我的 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
        

        【讨论】:

          【解决方案4】:

          您可以使用 Boost.Preprocessor 生成不同的参数计数,但我真的看不出这样做的好处。只需完成一次繁重的工作,将其塞入标题中即可完成。您正在节省自己的编译时间并拥有您的make_unique

          Here 是我的 make_unique.h 标头的复制粘贴,可模拟最多 5 个参数的可变参数模板。


          由于 OP 似乎不喜欢复制粘贴工作,这里是生成上述内容的 Boost.Preprocessor 代码:

          首先,制作一个包含多次模板头的主头(Boost.Preprocessor 迭代代码公然从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
          

          现在制作一个模板头,它会一次又一次地被包含并根据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
          

          【讨论】:

          • 谢谢,但我知道该怎么做。我的问题是关于以后不太可能造成维护问题的版本。我了解此类代码存在问题并需要修改的更改很少,但是如果我不允许将此类内容放入代码库中怎么办?
          • @Klaim:添加了 Boost.Preprocessor 代码以生成 make_unique 重载(使用 Clang 和 -E 编译器标志测试)。
          • 等等,为什么要手动说“0, 1, 2, 3, 4, 5...”?为什么不使用 Boost.PP 的迭代?
          • (顺便可以用BOOST_PP_COMMA_IF(MAKE_UNIQUE_NUM_ARGS)。)
          • @GManNickG:因为我不明白那个迭代是如何工作的,所以我只使用过手动的(那是很久以前的事了,写这个答案时必须查一下)。不过,感谢COMMA_IF,这是“最近”的补充吗?我从 Boost.Function 学习了可变参数仿真,它们也有一个单独的 BOOST_FUNCTION_COMMA(建议在编写 Boost.Function 时 COMMA_IF 不存在)。
          【解决方案5】:

          尽管可变参数模板不是 VS2012 的一部分,但头文件 &lt;memory&gt; 中内置了宏来帮助模拟它们。

          参见this very nice answer,它展示了如何在几行神秘的代码中实现make_unique&lt;T&gt;。我确认它运行良好:

          #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
          

          【讨论】:

            【解决方案6】:

            使用可变参数列表模拟函数的唯一方法是创建一个合适的重载列表。无论是手动完成,使用 Boost 预处理器库之类的东西,还是使用合适的生成器,都一样:无法模拟真正的可变参数列表。就个人而言,我认为模拟可变参数列表最可维护的版本是使用支持它们的编译器作为预处理器,并让它生成适合由尚未支持可变参数模板的编译器编译的代码。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2019-08-23
              • 2018-08-09
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-03-16
              • 2019-09-20
              相关资源
              最近更新 更多