简化模板

时间:2010-04-08 04:30:32

标签: c++ templates

我有一堆用于rpc的模板,并且想知道是否有一种方法可以简化它们,因为它重复它自我分配。我知道模板的varags会出现在下一个标准中,但你能为模板做默认值吗?

还有办法将void返回函数作为普通函数处理吗? Atm我必须将它们分开并将它们视为两个不同的东西,因为模板不会因为类型而变得无效。

template <typename R>
R functionCall(IPC::IPCClass* c, const char* name)
{
 IPC::IPCParameterI* r = c->callFunction( name, false );
 return handleReturn<R>(r);
}

template <typename R, typename A>
R functionCall(IPC::IPCClass* cl, const char* name, A a)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a));
 return handleReturn<R>(r);
}

template <typename R, typename A, typename B>
R functionCall(IPC::IPCClass* cl, const char* name, A a, B b)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b) );
 return handleReturn<R>(r);
}

template <typename R, typename A, typename B, typename C>
R functionCall(IPC::IPCClass* cl, const char* name, A a, B b, C c)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c) );
 return handleReturn<R>(r);
}

template <typename R, typename A, typename B, typename C, typename D>
R functionCall(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d) );
 return handleReturn<R>(r);
}

template <typename R, typename A, typename B, typename C, typename D, typename E>
R functionCall(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e) );
 return handleReturn<R>(r);
}

template <typename R, typename A, typename B, typename C, typename D, typename E, typename F>
R functionCall(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e, F f)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e), IPC::getParameter(f) );
 return handleReturn<R>(r);
}








inline void functionCallV(IPC::IPCClass* cl, const char* name)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false );
 handleReturnV(r);
}

template <typename A>
void functionCallV(IPC::IPCClass* cl, const char* name, A a)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a));
 handleReturnV(r);
}

template <typename A, typename B>
void functionCallV(IPC::IPCClass* cl, const char* name, A a, B b)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b) );
 handleReturnV(r);
}

template <typename A, typename B, typename C>
void functionCallV(IPC::IPCClass* cl, const char* name, A a, B b, C c)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c) );
 handleReturnV(r);
}

template <typename A, typename B, typename C, typename D>
void functionCallV(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d) );
 handleReturnV(r);
}

template <typename A, typename B, typename C, typename D, typename E>
void functionCallV(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e) );
 handleReturnV(r);
}

template <typename A, typename B, typename C, typename D, typename E, typename F>
void functionCallV(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e, F f)
{
 IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e), IPC::getParameter(f) );
 handleReturnV(r);
}










inline void functionCallAsync(IPC::IPCClass* cl, const char* name)
{
 IPC::IPCParameterI* r = cl->callFunction( name, true );
 handleReturnV(r);
}

template <typename A>
void functionCallAsync(IPC::IPCClass* cl, const char* name, A a)
{
 IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a));
 handleReturnV(r);
}

template <typename A, typename B>
void functionCallAsync(IPC::IPCClass* cl, const char* name, A a, B b)
{
 IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a), IPC::getParameter(b) );
 handleReturnV(r);
}

template <typename A, typename B, typename C>
void functionCallAsync(IPC::IPCClass* cl, const char* name, A a, B b, C c)
{
 IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c) );
 handleReturnV(r);
}

template <typename A, typename B, typename C, typename D>
void functionCallAsync(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d)
{
 IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d) );
 handleReturnV(r);
}

template <typename A, typename B, typename C, typename D, typename E>
void functionCallAsync(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e)
{
 IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e) );
 handleReturnV(r);
}

template <typename A, typename B, typename C, typename D, typename E, typename F>
void functionCallAsync(IPC::IPCClass* cl, const char* name, A a, B b, C c, D d, E e, F f)
{
 IPC::IPCParameterI* r = cl->callFunction( name, true, IPC::getParameter(a), IPC::getParameter(b), IPC::getParameter(c), IPC::getParameter(d), IPC::getParameter(e), IPC::getParameter(f) );
 handleReturnV(r);
}

根据要求提供额外代码:

template <typename R>
R handleReturn(IPC::IPCParameterI* r)
{
    if (r->getType() == PException::getTypeS())
    {
        gcException gce((gcException*)r->getValue());
        safe_delete(r);
        throw gce;
    }

    R temp = IPC::getParameterValue<R>(r, true);
    safe_delete(r);
    return temp;
}

inline void handleReturnV(IPC::IPCParameterI* r)
{
    if (r->getType() == PException::getTypeS())
    {
        gcException gce((gcException*)r->getValue());
        safe_delete(r);
        throw gce;
    }

    safe_delete(r);
    return;
}

2 个答案:

答案 0 :(得分:2)

对于变量参数,您无能为力。您可以使用Boost.Preprocessor生成函数,但如果这是一个选项,您也可以使用他们的Boost.Bind库。

  

还有一种方法可以将void函数作为普通函数来处理

你真的可以。以下是一个好的:

void foo(void)
{
    // sup
}

void bar(void)
{
    return foo();
}

void baz(void)
{
    return bar();
}

void lolwut(void)
{
    return baz();
}

它只是没有做任何事情,回归。


所以你想要的是:

// snipping for conciseness, obviously this applies to all variants
template <typename R>
R functionCall(IPC::IPCClass* c, const char* name)
{
    IPC::IPCParameterI* r = c->callFunction( name, false );
    return handleReturn<R>(r);
}

template <typename R, typename A>       // taking as const& to avoid copy
R functionCall(IPC::IPCClass* cl, const char* name, const A& a)
{
    IPC::IPCParameterI* r = cl->callFunction( name, false, IPC::getParameter(a));
    return handleReturn<R>(r);
}

您只需按正常方式调用它,当返回类型为void时,将void设为R。退货将被视为return;

然后问题变为handleReturn函数。您需要一个编译时if语句,以根据R是否为void来路由到正确的函数。这是一个基本的类型特征(就类型的查询而言)框架:

// any constant-expression can be turned into a type
// that can be instantiated, true and false generate
// different types
template <bool B>
struct bool_type
{
    static const bool value = B;
};

// the two fundamental types that will be generated
typedef bool_type<true> true_type; // the expression was true
typedef bool_type<false> false_type; // the expression was false

// mark functions that take a bool_type result...
typedef const true_type& true_tag; // ...as "the result was true"
typedef const false_type& false_tag; // ...or "the result was false"

这是类型特征系统的核心。考虑:

void foo(true_tag); // B was true
void foo(false_tag); // B was not true

void foo(void)
{
    static const bool B = true;
    foo( bool_type<B>() );
}

根据B是否为真,我们将转到不同版本的footrue_tag变体或false_tag变体。在继续之前,请确保您理解这一部分。

我们现在使用模板特化来生成一个继承自bool_type的类型,并且是true_typefalse_type,具体取决于该特征是否为真。对我们来说:

template <typename T> // in general, T is not a void...
struct is_void : bool_type<false>
{
    typedef T type;    
};

template <> // ...but in this case it is
struct is_void<void> : bool_type<true>
{
    typedef void type;
};

现在我们可以根据某种类型void选择一个函数:

void foo(true_tag); // R was void
void foo(false_tag); // R was not void

template <typename R>
void foo(void)
{
    // either inherits from true_type or false_type
    // and goes to the respective function
    foo( is_void<R>() );
}

或适用于我们的情况:

// I put all my detail functions in a namespace called detail,
// whether or not you do the same is up to you
namespace detail 
{
    template <typename R> // not void variant
    R getReturn(IPC::IPCParameterI* r, false_tag)
    {
        R temp = IPC::getParameterValue<R>(r, true);
        safe_delete(r);
        return temp;
    }

    template <typename R> // void variant
    R getReturn(IPC::IPCParameterI*, true_tag)
    {
        // do nothing
    }
}

template <typename R>
R handleReturn(IPC::IPCParameterI* r)
{
    // applies to both
    if (r->getType() == PException::getTypeS())
    {
        gcException gce((gcException*)r->getValue());
        safe_delete(r);
        throw gce;
    }

    // but now route to the correct version
    return detail::getReturn<R>(r, is_void<R>());
}

此代码对void返回类型的关注重复最少。

答案 1 :(得分:2)

太棒了!让我们玩得开心:))

实际上可以在没有varargs的情况下自动计算所有这些模板。它只需要预编程器编程,所以首先让我们看一下Boost.Preprocessor

首先,我们需要设计一个宏来处理实际的函数定义:

#define FUNCTION_CALL_IPC(z, n, data)\
  IPC::getParameter( BOOST_PP_CAT(data, n) )

#define FUNCTION_CALL(z, n, data)                               \
  template <                                                    \
    class R                                                     \
    BOOST_ENUM_TRAILING_PARAM(n, class Arg)                     \
  >                                                             \
  R functionCall(IPC::IPCClass* cl, const char* name            \
    BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(n, Arg, const& arg)    \
  )                                                             \
  {                                                             \
    IPC::IPCParameterI* r = cl->callFunction(name, false        \
      BOOST_PP_ENUM_TRAILING(n, FUNCTION_CALL_IPC, arg)         \
    );                                                          \
    return handleReturn<R>(r);                                  \
  }

// From 0 to 9 arguments
BOOST_PP_REPEAT(10, FUNCTION_CALL, ~)

瞧。

结合Gman处理void的诀窍,你已经完成了!