упрощающие шаблоны - PullRequest
       1

упрощающие шаблоны

4 голосов
/ 08 апреля 2010

У меня есть куча шаблонов, которые используются для rpc, и мне было интересно, есть ли способ упростить их, так как он повторяет их самостоятельно.Я знаю, что varags для шаблонов придет в следующем стандарте, но вы можете сделать значения по умолчанию для шаблонов?

Также есть ли способ обрабатывать возвращаемые пустые функции как обычные функции?Atm, я должен разделить их и обращаться с ними как с двумя разными вещами, поскольку шаблоны не воспринимают void как тип.

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 ]

2 голосов
/ 08 апреля 2010

О, здорово! Давайте веселиться:)

Эффективно можно автоматически вычислять все эти шаблоны без 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, ~)

И вуаля.

В сочетании с трюком Гмана для обработки void, все готово!

2 голосов
/ 08 апреля 2010

Для переменных аргументов вы мало что можете сделать.Вы можете использовать Boost.Preprocessor для генерации функций, но если бы это была опция, вы могли бы также использовать их библиотеку Boost.Bind .

ТакжеЕсть ли способ обрабатывать пустые функции как обычные функции

Вы действительно можете.Следующее нормально:

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 истинным или нет, мы будем направлять на другую версию foo, либо вариант true_tag, либо вариант false_tag.Прежде чем двигаться дальше, убедитесь, что вы понимаете эту часть.

Теперь мы используем специализацию шаблонов для генерации типа, который наследуется от bool_type и имеет значение true_type или false_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 типов возврата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...