将构造函数参数传递给模板函数工厂

3

I have this function:

template <class T> 
T *allocate()
{
    T *obj = new(top) T();
    top += sizeof(T);
    return obj;
}

现在,使用默认构造函数创建对象时很好用,但如何创建需要传递新参数的对象呢?
我知道可以使用C++11的可变模板来实现,但如果没有C++11功能,该怎么做呢?(显然,我的VS2012版本尚不支持此功能,但即使升级可以解决此问题,我也想知道如何在没有此功能的情况下进行操作)

您可以使用0、1、2、... N个参数的多个重载来模拟可变参数模板。可以使用Boost.Preprocesser来生成它们。 - Angew is no longer proud of SO
你可以尝试使用C宏来实现,但这是危险的,大多数C++指南不鼓励这样做。 - GuLearn
4个回答

4

没有一种语言特性可以替代可变参数模板(当然,否则它们就不会被发明出来)。

您可以提供几个重载函数,每个函数接受多达 N 个参数(对于合理的 N 选择)。每个重载函数将完美转发其参数到 T 的构造函数中。

因此,除了空函数模板之外:

template <class T>
T *allocate()
{
    T *obj = new(top) T();
    top += sizeof(T);
    return obj;
}

You will have a unary function template:

template <class T, class P1>
T *allocate(P1&& p1)
{
    T *obj = new(top) T(std::forward<P1>(p1));
    top += sizeof(T);
    return obj;
}

一个二元函数模板:
template <class T, class P1, class P2>
T *allocate(P1&& p1, P2&& p2)
{
    T *obj = new(top) T(std::forward<P1>(p1), std::forward<P2>(p2));
    top += sizeof(T);
    return obj;
}

一个三进制函数模板:
template <class T, class P1, class P2, class P3>
T *allocate(P1&& p1, P2&& p2, P3&& p3)
{
    T *obj = new(top) T(std::forward<P1>(p1), std::forward<P2>(p2), 
                        std::forward<P3>(p3));
    top += sizeof(T);
    return obj;
}

等等(你明白的)。如果你关心代码复制,你可以想出一些宏来减轻痛苦 - 但是它们并不能完全消除痛苦,特别是如果你不喜欢宏。

不要忘记:

#include <utility>

要使用std::forward<>(),您需要访问它。


std::forward 不是 C++11 的一部分吗?楼主询问如何在没有 C++11 功能的情况下完成它。 - zindorsky
2
@zindorsky:我认为OP对VC11支持的功能感兴趣。完美转发是被支持的。 - Andy Prowl

1
如果您可以使用boost,那么您可以使用boost::in_place_factory代替http://www.boost.org/doc/libs/1_35_0/libs/utility/in_place_factories.html
template <class InplaceFactory> 
T *allocate(InplaceFactory const & fac)
{
    T *obj = reinterpret_cast<T*>(top);
    fac.template apply<T>(obj)
    top += sizeof(T);
    return obj;
}

并使用:

T * a = allocate(boost::in_place(val, boost::ref(ref_value)));

PS 不要这样做:

T * a = allocate(boost::in_place());

你可以添加重载:
T *allocate(){ return allocate(boost::in_place()); }

1

你不仅需要可变参数模板,还需要C++11的完美转发能力。

如果你没有C++11功能,可以尝试模拟它,至少对于一组有限数量的参数是可能的。但这并不容易或美观。例如,可以参考boost实现的boost::tuple


0

如果您不想使用可变模板,可能需要在设计方面做出一些妥协:

struct empty {};
template<typename ObjectType,unsigned int ARG_LENGTH = 0,
         typename arg0=empty,
         typename arg1=empty,
         typename arg2=empty,
         typename arg3=empty,
         typename arg4=empty>
ObjectType* allocate(const arg0& a0, 
                     const arg1& a1,
                     const arg2& a2,
                     const arg3& a3,
                     const arg4& a4){
   ObjectType * obj = 0;
   switch(ARG_LENGTH){
     case 0: obj = new(top) ObjectType();break;
     case 1: obj = new(top) ObjectType(arg0);break;
     case 2: obj = new(top) ObjectType(arg0,arg1);break;
     case 3: obj = new(top) ObjectType(arg0,arg1,arg2);break;
     case 4: obj = new(top) ObjectType(arg0,arg1,arg2,arg3); break;
     default: obj = new(top) ObjectType(); break;
   }
   top += sizeof(T);
   return obj;
}

不确定是否能编译通过,但你明白我的意思。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接