Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ConsoleApplication1.cpp : Defines the entry point for the console application.
- //
- #include "stdafx.h"
- #include <iostream>
- #include <memory>
- #include <unordered_map>
- #include <vector>
- #include <utility>
- #include <tuple>
- #include <string>
- #include <type_traits>
- #include <memory>
- /*a replacement for std::optional for default values that may or may not exist*/
- template<typename T>
- struct Optional
- {
- Optional() { }
- Optional(T const& v) : v(std::make_unique<T>(v)) { }
- Optional(T&& v) : v(std::make_unique<T>(std::forward<T>(v))) { }
- operator bool() const { return v.operator bool(); }
- std::unique_ptr<T> v;
- };
- /*dummy player class for testing, contains various functions to test binding with*/
- struct Player {
- void SetName(std::string const & name) {
- std::cout << "Called " << name << std::endl;
- }
- std::string SetName2(std::string const & name) {
- return name;
- }
- void overloaded(int i) {
- std::cout << "Called " << i << std::endl;
- }
- void overloaded(double d) {
- std::cout << "Called " << d << std::endl;
- }
- void multiple_parameters(int a, double b, std::string c, const char* d) {
- std::cout << "Called " << a << b << c << d << std::endl;
- }
- void alltypes(int a, std::string b, const char* c, void* d, std::string const & e) {
- std::cout << "Called " << a << b << c << d << e << std::endl;
- }
- std::string& refreturn() {
- static std::string ref = "ref";
- return ref;
- }
- std::string* ptrreturn() {
- static std::string ref = "ptr";
- return &ref;
- }
- };
- /*this class represents the lua stack interface which allows pushing and reading(checking) values from the stack*/
- struct State {
- State(void*) {}
- template<typename T> void Push(T v) { std::cout << "Pushed: " << v << std::endl; };
- template<typename T> T CHECKVAL(int i, T def) { return def; };
- template<typename T> T CHECKVAL(int i) { return T(); };
- };
- /*a base function type, this will be used to store functions in some place for simple access to make function calls.
- Different implementations of binding functions can inherit this and override how the function is called*/
- class fbase
- {
- public:
- fbase(std::string const& name) : name(name) {};
- virtual ~fbase() = default;
- virtual int call(State& state) = 0;
- std::string name;
- };
- /*This is a specialized class to store function signatures and call the functions with values from lua stack later on*/
- template<
- typename F, /*real function pointer signature*/
- typename R, /*type used for pushing return value to stack. Can be void to not push anything even if there is a return value*/
- typename C, /*type used the check the object itself from stack (type of self)*/
- typename... P /*types used for checking values from stack to be used as function parameters*/
- >
- class func : public fbase
- {
- public:
- typedef std::tuple<Optional<P>...> Defaults;
- typedef std::tuple<P...> Arguments;
- static constexpr auto size = std::tuple_size<Arguments>::value;
- static constexpr auto seq = std::make_index_sequence<size>{};
- func(std::string const& name, F f) : fbase(name), f(f), d() { }
- template<typename ...T, typename = std::enable_if<(size > 0)>>
- func(std::string const& name, F f, T&&... args) : fbase(name), f(f), d(std::forward<T>(args)...) { }
- /*override the base method that should call a function.*/
- int call(State& state) override
- {
- C sel = state.CHECKVAL<C>(0); // self is at idx 0
- Arguments args;
- fill_tuple(state, args, seq); // check parameters from stack
- return call_function(state, sel, args, seq); // call function with self and the parameters
- }
- /*allows setting a default value for some specific parameter index, for example if function is (int,double), you can do func(...).def<1>(1.5)*/
- template <size_t I, typename T>
- auto& def(T&& t)
- {
- std::get<I>(d) = typename std::tuple_element<I, Defaults>::type(std::forward<T>(t));
- return *this;
- }
- private:
- /*helper function to fill to tuple a single value checked from stack at index I */
- template <size_t I>
- void fill_tuple_helper(State& state, Arguments& args)
- {
- auto& v = std::get<I>(args);
- auto const & def = std::get<I>(d);
- // self is at idx 0, so parameters start at 1, which means we need to use I+1
- if (def)
- v = state.CHECKVAL<typename std::tuple_element<I, Arguments>::type>(I + 1, *def.v);
- else
- v = state.CHECKVAL<typename std::tuple_element<I, Arguments>::type>(I + 1);
- }
- /*fill tuple by checking values at given template argument indexes*/
- template <size_t ... I>
- void fill_tuple(State& state, Arguments& args, const std::index_sequence<I ...>&)
- {
- // Calling a function for each type in a tuple from https://stackoverflow.com/questions/16387354/template-tuple-calling-a-function-on-each-element
- auto l = { 0, (fill_tuple_helper<I>(state, args), 0)... };
- }
- /*call the function with the tuple of parameters. Since return type is defined as void, dont push anything after calling the function*/
- template<size_t ... I, typename T = R>
- typename std::enable_if<std::is_void<T>::value, int>::type
- call_function(State&, C& o, Arguments& args, const std::index_sequence<I ...>&)
- {
- // Arguments parameter unpacking from https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer
- (o->*f)(std::get<I>(args) ...);
- return 0;
- }
- /*call the function with the tuple of parameters. Since there is a return value, we push it to stack after calling the function*/
- template<size_t ... I, typename T = R>
- typename std::enable_if<!std::is_void<T>::value, int>::type
- call_function(State& state, C& o, Arguments& args, const std::index_sequence<I ...>&)
- {
- state.Push<R>((o->*f)(std::get<I>(args) ...));
- return 1;
- }
- F f;
- Defaults d;
- };
- int main() {
- State s(nullptr);
- func<void (Player::*)(std::string const &), void, Player*, std::string>("SetName", &Player::SetName).def<0>("teasdstd").call(s);
- func<decltype(&Player::SetName), void, Player*, std::string>("SetName", &Player::SetName).def<0>("teasdst").call(s);
- func<decltype(&Player::SetName2), std::string, Player*, std::string>("SetName2", &Player::SetName2).call(s);
- func<decltype((void (Player::*)(int))&Player::overloaded), void, Player*, int>("overloaded", &Player::overloaded).def<0>(5).call(s);
- func<decltype(&Player::multiple_parameters), void, Player*, int, double, std::string, const char*>("multiple_parameters", &Player::multiple_parameters).def<1>(1.5).def<2>("asd").def<3>("cstr").call(s);
- func<decltype(&Player::alltypes), void, Player*, int, std::string, const char*, void*, std::string>("alltypes", &Player::alltypes).def<2>("cstr").def<3>(nullptr).def<4>("strref").call(s);
- func<decltype(&Player::alltypes), void, Player*, int, std::string, const char*, void*, std::string>("alltypes", &Player::alltypes, 1, std::string("asd"), "bsd", nullptr, std::string("asd")).call(s);
- func<decltype(&Player::refreturn), std::string, Player*>("refreturn", &Player::refreturn).call(s);
- func<decltype(&Player::ptrreturn), std::string*, Player*>("ptrreturn", &Player::ptrreturn).call(s);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement