2009-07-15 2 views
6

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

// this is what we want the wrapped function to look like 
typedef void (*callback)(int); 
void foobar(float x); // wrappee 

// doesn't compile 
template< T (*f)(S) > // non-type template param, it's a function ptr 
struct Wrapper 
{ 
    static void wrapped(int x) 
    { 
    // do a bunch of other stuff here 
    f(static_cast<S>(x)); // call wrapped function, ignore result 

    } 
} 

и тогда я хотел бы сделать что-то вроде:

AddCallback(Wrapper<foobar>::wrapped); 

Однако, проблема в том, что я не могу просто идти вперед и использовать «S» в параметре функции в шаблоне Wrapper, я должен сначала перечислить его как параметр:

template< class T, class S, T (*f)(S) > 
struct Wrapper 
// ... 

Но это означает, что гораздо больнее использовать (Wrapper<void,float,foobar>::wrapped), в идеале я хотел бы просто передать указатель функции там, и он автоматически будет обрабатывать типы параметров (и возвращаемых типов). Чтобы быть ясным, внутри завернутой функции мне нужно будет обратиться к типам указателя функции (так что мне нужен какой-то эквивалент S или T).

Есть ли способ сделать это?

+0

@damndirtyape: Я думал о вашем вопросе, и я думаю, что сделал что-то подобное. К сожалению, это связано с большим количеством кода. В основном, у моего решения был базовый класс, который перегружал operator(), и у меня были заводские функции, которые построили базовые классы, основанные на переданном типе функции. Если вам нравится, я могу разместить код в пастебине где-нибудь. –

ответ

0

Если вы используете функцию, которая возвращает «завернутый», а не ссылается на нее напрямую, компилятор попытается автоматически сопоставить параметры шаблона для вызова функции.

Редактировать: Как насчет этого?

int foobar(float x); // wrappee 

template <typename T, typename S> 
struct Wrapper { 
    typedef T (*F)(S); 
    F f; 

    Wrapper(F f) : f(f) { } 

    void wrapped(S x) { 
     // do a bunch of other stuff here 
     f(x); // call wrapped function, ignore result 
    } 
}; 

template <typename T, typename S> 
Wrapper<T,S> getWrapper(T (*f)(S)) { 
    return Wrapper<T,S>(f); 
} 

... 
getWrapper(foobar).wrapped(7); 
+0

Это не решает проблему, потому что теперь параметры шаблона для этой функции имеют одинаковую проблему. – damndirtyape

+0

Вы уверены? Возможно, я просто не понимаю, что вы пытаетесь сделать ... –

+0

Не работает, потому что вы изменили функцию из статического метода как метода экземпляра, но все дело в том, чтобы сделать завернутую функцию соответствующей существующая сигнатура обратного вызова (что означает, что она должна быть статической). – damndirtyape

0

EDIT: совершенно новый ответ

ОК, я полностью повторно думал вопрос и считаю, что я получаю то, что вы хотите. Я сделал это раньше: -P.

Вот идея, у меня есть класс Base, который перегружает operator(), тогда у меня есть подкласс для каждой «arity» функций. Наконец, у меня есть заводская функция, которая вернет одну из этих вещей. Код большой (и, вероятно, немного перебор), но работает красиво. Большая часть перегрузок library_function предназначена для поддержки разных синтаксисов, в основном ненужных. Он также поддерживает функции boost::bind, функции-члены и т. Д., Намного больше, чем вам, вероятно, нужно.

http://pastebin.com/m35af190

Пример, использование:

// map of library functions which will return an int. 
std::map<std::string, LibraryFunction<int> > functions; 

// function to register stuff in the map 
void registerFunction(const std::string &name, LibraryFunction<int> func) { 
    functions.insert(std::make_pair(name, func)); 
} 

позже вы можете сделать это:

// the this param is so the function has access to the scripting engine and can pop off the parameters, you can easily chop it out 

// register 2 functions, one with no params, one with 1 param 
registerFunction("my_function", library_function1(*this, call_my_function)); 
registerFunction("my_function2", library_function0(*this, call_my_function2)); 

functions["my_function"](); 
functions["my_function2"](); 
+0

Это не позволяет мне обернуть существующую функцию, я должен написать новый объект, что означает, что мне все же нужно указывать типы спереди, а не их вывод? – damndirtyape

+0

Я не вижу, как это помогает мне. В основном у меня есть специальная подпись обратного вызова (которой у меня нет контроля), мне нужно обернуть большое количество существующих функций C, чтобы они соответствовали этой сигнатуре обратного вызова (это привязка к скрипту, поэтому для функции параметров 3 мне нужно поп 3 значения из стека, передайте их в обертку и снова верните результат в стек, но внешне каждая отдельная функция имеет ту же подпись). – damndirtyape

+0

Опять же, это не помогает. Мне нужно превратить его в указатель функции, совместимый с фиксированной сигнатурой обратного вызова. Это не так. Мне нужно включить функцию, которая берет строку (скажем) функции, которая соответствует обратному вызову, выполняя некоторую магию (нажав строку на стек и т. Д.) Внутри функции, но подпись этой завернутой функции * должна * соответствуют обратному вызову. – damndirtyape

0

Я смотрел на импульс. При первом чтении вашего вопроса мне кажется, что <boost/function_types/parameter_types.hpp> предоставляет то, что вам нужно.

+0

Не очень хороший ответ: без указания ссылки на соответствующую библиотеку повышения, это похоже на высказывание «Поиск в Google, я думаю, что там лежит ответ». Более того, я не вижу ничего в Boost, который может выполнять требования OP. Не могли бы вы быть более конкретными в своем ответе? –

+0

У меня было. Я использовал напрямую <et> вместо объектов HTML и имя заголовка было скрыто. Я отредактировал свой ответ, чтобы исправить это. – AProgrammer

+0

А в комментариях не нужны сущности, а < and > работает ... ну, я все еще изучаю интерфейс. – AProgrammer

5

Одна вещь, которую вы, возможно, захотите рассмотреть, - это использование LLVM или аналогичного для создания соответствующей функции батута во время выполнения.Или вот статическое решение:

#include <iostream> 

void f(float f) { std::cout << f << std::endl; } 

template<typename T, typename S> struct static_function_adapter { 
     template<T(*f)(S)> struct adapt_container { 
       static void callback(int v) { 
         f(static_cast<S>(v)); 
       } 
     }; 

     template<T(*f)(S)> adapt_container<f> adapt() const { 
       return adapt_container<f>(); 
     } 
}; 

template<typename T, typename S> struct static_function_adapter<T, S> get_adapter(T (*)(S)) { 
     return static_function_adapter<T, S>(); 
} 

#define ADAPTED_FUNCTION(f) (&get_adapter(f).adapt<f>().callback) 

int main() { 
     void (*adapted)(int) = ADAPTED_FUNCTION(f); 
     adapted(42); 
     return 0; 
} 

Функция get_adapter позволяет нам вывести аргумент и тип возвращаемого значения; adapt() затем преобразует это в тип, параметризованный по фактической функции, и, наконец, мы получаем статическую функцию в обратном вызове.

+0

Я просто не знаю, что должен делать этот код и какую проблему он должен решить: O – Virus721

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