_pv 64 5 сентября, 2021 Опубликовано 5 сентября, 2021 · Жалоба решил тут посмотреть что там нынче современные плюсы умеют вот есть обычные С функции, например int f1(double a); void f2 (double b, const char * с); ... хочется сделать для них некую простую обёртку, без лишней писанины, lua_push(L, f1); которая во время компиляции сгенерит шаблонную функцию в зависимости от типа аргументов, которая уже достанет соответственно типам аргументы, позовёт саму оборачиваемую функцию и получит возвращаемое значение. lua тут просто для примера. обёрнуто ещё раз в шаблонную функцию, а не в стуктуру, потому что там какие-то грабли были с перегрузкой конструктора если вдруг не только указатели на функции передавать. template <typename T, typename ...Args> void lua_push(lua_State * L, T(*value)(Args...)){ push<0, T, Args...>(L, value); }; template <> void lua_push(lua_State * L, int value){lua_pushinteger(L, value);} template <> void lua_push(lua_State * L, double value){lua_pushnumber(L, value);} template <> void lua_push(lua_State * L, const char * value){lua_pushstring(L, value);} template <> void lua_push(lua_State * L, int(*value)(lua_State*)){lua_pushcfunction(L, value);} template <int N, typename T, typename ...Args> struct push{ push(lua_State * L, T(* func)(Args...)){ push::m_func = func; lua_push(L, push::cfunc); } static T(*m_func)(Args...); static int cfunc (lua_State * L){ lua_push(L, m_func((lua_check<Args>(L, 1))...)); return 1; } }; в луа отдаётся статическая функция-обёртка push::cfunc и соответственно сам указатель на функцию сохраняется в статический же push::m_func. template <int N, typename T, typename ...Args> T(*push<N, T,Args...>::m_func)(Args...); это не совсем работает из-за того что разные функции с одинаковыми типами возвращаемых значений и аргументов перезапишут общий для них m_func. сам указатель из агрумента функции вытащить в константный параметр шаблона не получилось, не смотря на то что constexpr auto func = &printf; вроде вполне законно, но при проходе через "аргумент" функции он константным быть перестаёт. а при указании в качестве параметра шаблона структуры template <typename T, typename ...Args, T(*Fp)(Args...)> в конец его поставить нельзя потому что вариативные Args... должны быть в конце, а до Args... нельзя потому что Args ещё не определён. причём для шаблонной функции позволяет сделать template <typename T, typename ...Args, T(*Fp)(Args...)>, но как вытащить сам указатель из аргумента функции lua_push? а при попытке всё же протащить адрес функции как int N в качестве первого параметра шаблона через всевозможные касты удалось даже поломать gcc: internal compiler error: in coerce_template_parms, at cp/pt.c:8519| может как-то по другому можно заставить всегда генерить разные шаблонные типы даже для одинаковых параметров шаблона? какой-нибудь compile time счётчик в качестве <int N> или рекурсию? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rkit 4 6 сентября, 2021 Опубликовано 6 сентября, 2021 · Жалоба Может быть не объявлять m_func статической, и она будет разной для разных функций? В любом случае, мало чего понятно. Людей, которые мастера шаблонов, и при этом знают, что такое lua_push, не так уж и много. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 64 6 сентября, 2021 Опубликовано 6 сентября, 2021 · Жалоба тогда до m_func не добраться из статической функции cfunc и надо где-то хранить и как-то передавать сам объект. пусть будет без lua, она тут просто для примера. хотелось для обычной функции сгенерить другую шаблонную функцию-обёртку, которая достанет откуда надо аргументы исходя из типов аргументов, позовёт исходную функцию с данными аргументами и положит куда надо результат. средствами компилятора, а не сторонними кодогенераторами или в рантайме. псевдокод: template <typename T, typename Args...> std::function<> wrap( T (*func)(Args...) ){ return [](){ Args ... args = get_agrs()...; T ret = func(args...); do_something(ret); } } f1 = wrap(sqrt); //double(*)(double) f2 = wrap(pow); //double(*)(double, double) f3 = wrap(getch); //char(*)(void) f1(); f2(); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rkit 4 6 сентября, 2021 Опубликовано 6 сентября, 2021 (изменено) · Жалоба Ну нужно сделать просто шаблон-структуру, для которой определен operator(), это будет твоя f1. В ней же хранить и m_func и cfunc. И посмотреть на std::apply. Самое интересное остается в реализации get_args(). Изменено 6 сентября, 2021 пользователем rkit Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 6 сентября, 2021 Опубликовано 6 сентября, 2021 · Жалоба 17 hours ago, _pv said: может как-то по другому можно заставить всегда генерить разные шаблонные типы даже для одинаковых параметров шаблона? Ну, допустим вы это даже как-то сгенерируете. Выбирать нужный вам вариант компилятор как будет? Вас точно не устраивает простейший вариант? void push(int i) { pushinteger(i); } void push(float f) { pushnumber(f); } Ну или полистайте гитхаб в поисках плюсовых обёрток для Луа. Там оно есть. 5 hours ago, rkit said: что такое lua_push Это десяток однотипных функций, чтобы поместить аргумент в стек перед вызовом функции в интерпретаторе луа (по отдельной функции для каждого типа аргумента). Можете посмотреть описание (https://www.lua.org/manual/5.3/manual.html раздел 4), там всё просто. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 64 6 сентября, 2021 Опубликовано 6 сентября, 2021 · Жалоба 9 minutes ago, esaulenka said: Ну, допустим вы это даже как-то сгенерируете. Выбирать нужный вам вариант компилятор как будет? Вас точно не устраивает простейший вариант? void push(int i) { pushinteger(i); } void push(float f) { pushnumber(f); } Ну или полистайте гитхаб в поисках плюсовых обёрток для Луа. Там оно есть. выбирать будет исходя из типа переданного значения. простейший вариант не устраивает если я захочу передать функцию void push(pow); для этого руками придётся сделать: int lua_pow(lua_State *L){ double arg0 = lua_tonumber(L,1); double arg1 = lua_tonumber(L,2); double ret = pow(arg0,arg1); lua_pushnumber(L, ret); return 1; } void push(pow); {pushcfunction (L, lua_pow);} при том что всё это компилятор мог бы сгенерить и сам по шаблону исходя из типа переданного ему pow: double(*)(double, double). и ещё раз, не в луа дело, я разобраться с шаблонами хочу. готовых обёрток действительно полно http://lua-users.org/wiki/BindingCodeToLua , последняя ссылка там более менее описывает то, чего хочется http://inspired-code.blogspot.com/p/automagical-language-bindings-using-c.html Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 64 6 сентября, 2021 Опубликовано 6 сентября, 2021 · Жалоба . Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_pv 64 7 сентября, 2021 Опубликовано 7 сентября, 2021 · Жалоба 23 hours ago, rkit said: Самое интересное остается в реализации get_args(). parameter pack умеет сам разворачиваться f(args)... <==> f(arg0), f(arg1), ... вот что пока получилось, единственное что не смог победить, это то что саму функцию приходится указывать два раза, один раз как параметр шаблона, но как void*, а другой раз как аргумент для получения типа. lua_push<(void*)func>(L, func); template <typename T> void lua_push(lua_State * L, T value); template <> void lua_push (lua_State * L, int value) { lua_pushinteger(L, value); } template <> void lua_push (lua_State * L, double value) { lua_pushnumber(L, value); } template <> void lua_push (lua_State * L, const char * value) { lua_pushstring(L, value); } template <> void lua_push (lua_State * L, int(*func)(lua_State *)) { lua_pushcfunction(L, func); } template <typename T> T lua_to(lua_State * L, int idx); template <> int lua_to (lua_State * L, int idx) { return lua_tointeger (L, idx); } template <> double lua_to (lua_State * L, int idx) { return lua_tonumber (L, idx); } template <> const char * lua_to (lua_State * L, int idx) { return lua_tostring (L, idx); } template<int ...> struct seq { }; template<int N, int ...S> struct gens : gens<N-1, N-1, S...> { }; template<int ...S> struct gens<0, S...> { typedef seq<S...> type; }; template <void* Fn, typename T, typename ... Args, int ... N> T callN(lua_State *L, int * retnum, seq<N...>){ return ((T(*)(Args...))Fn)(lua_to<Args>(L, N+1)...); } template <void* Fn, typename T, typename ... Args> T call(lua_State * L, int * retnum){ return callN<Fn,T,Args...>(L, retnum, typename gens<sizeof...(Args)>::type ()); } template <void* Fn, typename T, typename ... Args> int lua_cfunc(lua_State * L){ int retnum = 0; if constexpr (std::is_void<T>::value) call<Fn,T,Args...>(L, &retnum); else { lua_push(L, call<Fn,T,Args...>(L, &retnum)); retnum += 1; } return retnum; } template <void* F, typename T, typename ... Args> void lua_push(lua_State * L, T(*)(Args...)){ lua_push(L, lua_cfunc<(void*)F, T, Args...>); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться