2016-08-06 4 views
3

Я пытаюсь написать Приостановка Service Routine в C++, вот некоторый фрагмент кодаКак сгенерировать функцию во время выполнения?

void handlerProxy(int intrNo) {} 

typedef void(*IntrHandler)(); 

IntrHandler IDT[256]; 

Я хочу, чтобы инициализировать IDT в время выполнения или во время компиляции, как это:

for (size_t i = 0; i < 256; ++i) { 
    // It doesn't compile 
    IDT[i] = std::bind(handlerProxy, i); 
    // or 
    IDT[i] = [i]() {handlerProxy(i);}; 
} 

проблема в том,

  • лямбда-функция захвата не может быть преобразован в указатель на функцию
  • Мой код будет скомпилирован с -fno-rtti, так std::function::target не доступен

Есть ли возможность мне удастся это сделать? Я не хочу писать IDT[0]= ... IDT[1]=... вручную или использовать другую программу для ее создания. Макро и встроенный asm разрешены. Тип IDT может быть изменен, однако элемент IDT должен быть адресом функции, что означает, что что-то вроде jmp IDT[0] должно быть действительным.

+0

Будет ли исключение типа 'IDT []' a 'sturct' с перегрузкой оператора функции (объект функции) не может быть и речи? – Galik

+0

@Galik В этом случае 'jmp IDT [0]' не будет работать. BIOS вызывает эти функции только с помощью 'push' регистров и флагов и' jmp' по адресу –

ответ

5

Вы могли бы сделать intrNo параметр шаблона следующим образом:

template <int intrNo> 
void handlerProxy() {} 

typedef void(*IntrHandler)(); 

и инициализировать массив, используя пакет расширения:

template <typename IS> 
struct helper; 

template <size_t ... Is> 
struct helper<std::index_sequence<Is...>> { 
    static constexpr std::array<IntrHandler, sizeof...(Is)> make_handlers() { 
    return {{ &handler_proxy<Is> ... }}; 
    } 
}; 

constexpr std::array<IntrHandler, 256> IntrHandlers = helper<std::make_index_sequence<256>>::make_handlers(); 

IntrHandler * IDT = IntrHandlers.data(); 

(пусть покупатель будет бдителен, код не проверял)

+0

. Он работает, хотя 'IntrHandlers.data()' не может быть назначен непосредственно на IntrHandler * '- просто нужно немного изменить. –

1

Криса ответ более компактный. Однако это можно сделать с помощью кортежа, определить handlerProxy как шаблонный функциональный объект со статическим членом:

template <int i> 
    struct handlerProxy{ 
    static int func(){return i * i;} 
}; 

затем работать, чтобы создать кортеж указателя на функции:

template <size_t... I> 
decltype(auto) functions(std::index_sequence<I...>) { 
     return return std::make_tuple(&handlerProxy<I>::func...); 
} 
template <size_t size> 
decltype(auto) generate_functions() {              
    using Indices = std::make_index_sequence<size>; 
    return functions(Indices{}); 
} 

использование:

int main() 
{ 
    //generate tuple of functions 
    auto IDT = generate_functions<256>(); 
    //call 2th function 
    std::cout << std::get<2>(IDT)(); 
} 

Примечание: опция -ftemplate глубина в НКУ должна быть установлена ​​на относительно большое количество, 50000 , для компиляции

+0

Я не думаю, что это может сработать. Обратите внимание, что в моем вопросе мне нужны такие вещи, как 'jmp IDT [0]'. Каждый элемент в IDT должен быть 32-разрядным. Хотя 'std :: get <2> (IDT)()' работает, но это BIOS, который будет вызывать эти функции. BIOS не знает 'operator()', BIOS только 'jmp' по адресу без каких-либо параметров. –

+0

Может быть, я могу использовать адрес '& handlerProxy <0> :: operator()', '& handlerProxy <1> :: operator()' ... для заполнения массива IDT, но я не уверен, что простой 'jmp' для этого адрес в asm всегда может вызвать функцию правильно. –

+0

Я имею в виду, что функция-член всегда имеет скрытый параметр 'this', но BIOS не будет передавать этот параметр, поэтому я не уверен, будут ли у него какие-то побочные эффекты. –

Смежные вопросы