2013-05-16 9 views
1

Я пишу размещенную программу на C++, которая запускает написанный пользователем C-код, скомпилированный на лету. Крайне важно, чтобы определенные типичные исключения были уловлены из C-кода и обработаны/проигнорированы. Для этого я вызываю код C из блока структурированных исключений. Из-за природы и семантики этого блока (и, где это вызывается из), я отделил фактическое призвание это собственной функции:Функция шаблона, принимающая вызываемые функторы с параметрами X

template <typename ret_type, class func> 
     static ret_type Cstate::RunProtectedCode(func function) { 
      ret_type ret = 0; 
      __try { 
       ret = function(); 
      } 
      __except(ExceptionHandler(GetExceptionCode(), ExceptionStatus::CSubsystem)) { 
       fprintf(stderr, "First chance exception in C-code.\n"); 
      } 
      return ret; 
     } 

, который работает хорошо, как это должно выглядеть примерно так:

 RunProtectedCode<int>(entry); 

Но можно ли это сформировать так, чтобы я мог вызывать функции с переменным количеством параметров - может быть, через некоторое использование экзотических функторов (только требование, очевидно, что у него не может быть деструктор)? Я использую MSVC++ 2010.

+0

Есть VARIADIC шаблоны, но я боюсь, что они не поддерживаются в VS 2010. – chris

+0

Не против обновления до VS2012, если это может быть совершенных там. Можете ли вы сделать пример кода? – Shaggi

+0

К сожалению, VS2012 также не поддерживает вариационные шаблоны. – Xeo

ответ

0

Вы можете связать все аргументы с вашей функцией, эффективно используя 0-арный функтор, например. используя std::bind (доступно в VC2010) или boost::bind (я предпочитаю это, потому что реализация VC содержит сломанные std::cref). Связывание может выполняться в перегруженной функции перед переходом на RunProtectedCode, например. что-то вроде этого:

template<typename R> 
R(*f)() wrap(R(*f)()) 
{ 
    return f; 
} 

template<typename R, typename A> 
boost::function<R(A)> wrap(R(*f)(), A a) 
{ 
    return boost::bind(f, a); 
} 

template<typename R, typename A1, typename A2> 
boost::function<R(A1, A2)> wrap(R(*f)(), A1 a1, A2 a2) 
{ 
    return boost::bind(f, a1, a2); 
} 
+0

Стоит также отметить, что в VS2010 копия 'std :: bind' конструирует свои аргументы примерно как 10 раз. 'boost :: bind' и VS2012' std :: bind' ведут себя лучше в этом отношении. –

2

Если вы можете использовать C++ 11, вы можете добиться этого с помощью переменных темпа.

template <typename ret_type, class func, typename... Args> 
    static ret_type Cstate::RunProtectedCode(func function, Args... args) { 
     ret_type ret = 0; 
     __try { 
      ret = function(args...); 
     } 
     __except(ExceptionHandler(GetExceptionCode(), ExceptionStatus::CSubsystem)) { 
      fprintf(stderr, "First chance exception in C-code.\n"); 
     } 
     return ret; 
    } 

А вы можете назвать это как

RunProtectedCode<int>(entry2, 1, 2); 
RunProtectedCode<int>(entry3, 1, "a", 3); 

Вы можете упростить его (вид) с помощью зЬй :: функции вместо.

template <class func, typename... Args> 
    static 
    typename func::result_type Cstate::RunProtectedCode(func function, Args... args) { 
     typename func::result_type ret = typename func::result_type(); 
     __try { 
      ret = function(args...); 
     } 
     __except(ExceptionHandler(GetExceptionCode(), ExceptionStatus::CSubsystem)) { 
      fprintf(stderr, "First chance exception in C-code.\n"); 
     } 
     return ret; 
    } 

А вы можете назвать это как

std::function<int(int,int,int)> entry_f = entry; 
RunProtectedCode(entry_f,1,2,3);