рдХрд┐рд╕реА рджрд┐рдП рдЧрдП рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЗ рдЕрдиреБрд░реВрдк рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рдирд╛

рдирдорд╕реНрддреЗ!

рдореБрдЭреЗ рдирд╣реАрдВ рдкрддрд╛ рдерд╛ рдХрд┐ рд▓реЗрдЦ рдХреЛ рдФрд░ рдЕрдзрд┐рдХ рд╕рдЯреАрдХ рд░реВрдк рд╕реЗ рдХреИрд╕реЗ рдирд╛рдо рджрд┐рдпрд╛ рдЬрд╛рдП, рд▓реЗрдХрд┐рди рдореИрдВ рдПрдХ рдЫреЛрдЯреА рдкрд╣реЗрд▓реА рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛, рдЬреЛ рдЗрд╕ рддрд░рд╣ рд╕реЗ рд▓рдЧрддрд╛ рд╣реИ:

рдЗрдирдкреБрдЯ рдХрд┐рд╕реА рддрд░рд╣ рд╕реЗ рддреИрдпрд╛рд░ рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдирд╛рдо, рдЙрд╕рдХреЗ рддрд░реНрдХ рдФрд░ рдкреНрд░рдХрд╛рд░ рдХреЗ рддрд░реНрдХ рдЗрдВрдЧрд┐рдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдЖрдкрдХреЛ рд╕рднреА рддрд░реНрдХреЛрдВ рдХреЛ рд╕рд╣реА рдврдВрдЧ рд╕реЗ рдкрд╛рд░рд┐рдд рдХрд░рддреЗ рд╣реБрдП, рдЙрдкрдпреБрдХреНрдд рдлрд╝рдВрдХреНрд╢рди рд╣реИрдВрдбрд▓рд░ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рд╣реЛрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред


рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЗрд╕рд▓рд┐рдП ActionScript рдкрд░реАрдХреНрд╖рдг рдлрд╝рдВрдХреНрд╢рди рдХреЛ рддреАрди рддрд░реНрдХреЛрдВ, рдЭреВрдард╛ , 1.0 (рдХреНрд░рдорд╢рдГ, рддрд░реНрдХреЛрдВ рдХреЗ рдкреНрд░рдХрд╛рд░: рд╕реНрдЯреНрд░рд┐рдВрдЧ , рдмреБрд▓рд┐рдпрди , рд╕рдВрдЦреНрдпрд╛ ) рдХреЗ рд╕рд╛рде рдХреЙрд▓ рдХрд░рдиреЗ рдХрд╛ рдкреНрд░рдпрд╛рд╕ рдХрд░рддрд╛ рд╣реИ:

<invoke name="test" returntype="xml"><arguments><string>str</string><false/><number>1.0</number></arguments></invoke>
      
      





рдореИрдВ C ++ рдХреЛ рдЗрд╕реА рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдХрд░рдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛:

 void test_handler(const std::wstring& str, bool flag, double n);
      
      







рдХрдЯреМрддреА рдХреЗ рддрд╣рдд - рдирдП рдорд╛рдирдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди, рдФрд░ рддреБрд▓рдирд╛ рдХреЗ рд▓рд┐рдП, рдкреБрд░рд╛рдиреЗ рдорд╛рдирдХ (рдФрд░ рдмреВрд╕реНрдЯ рдХреА рдмреВрдВрджреЛрдВ) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрдиред



рдЪрд▓рд┐рдП рд╢реБрд░реВ рдХрд░рддреЗ рд╣реИрдВред рдкрд╣рд▓реЗ рдЖрдкрдХреЛ рдХрд┐рд╕реА рддрд░рд╣ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рдпрд╣ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╕рд╛рд░ рдирд╣реАрдВ рд╣реИ, рд╣рдо xml рдХреЛ рдкрд╛рд░реНрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП Boost.PropertyTree рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реЗрдВрдЧреЗред рд╣рдо рдпрд╣ рд╕рдм рд╕рд╣рд╛рдпрдХ рд╡рд░реНрдЧ InvokeParser



, рдЬреЛ рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдирд╛рдо рдФрд░ рддрд░реНрдХ рдХреЗ рдЬреЛрдбрд╝реЗ рдХреА рдПрдХ рд╕рд░рдгреА рдЯрд╛рдЗрдк рдХрд░реЗрдЧрд╛-рдЗрд╕рдХрд╛ рдорд╛рди :

InvokeParser
 #include "boost/property_tree/ptree.hpp" #include "boost/property_tree/xml_parser.hpp" namespace as3 { class InvokeParser { public: using ArgsContainer = std::vector< std::pair< std::wstring, // Argument type std::wstring // Argument value >>; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); // Are 'invoke' tag attributes and 'arguments' tag exists? auto invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); auto arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; // Is 'name' exists ? auto name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(const auto& arg_value_pair : *arguments_xml) { std::wstring arg_type = arg_value_pair.first; std::wstring arg_value = arg_value_pair.second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.emplace_back(arg_type, arg_value); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; }; } // as3
      
      









рдЕрдм рд╣рдо рдПрдХ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдХреНрд▓рд╛рд╕ Type



рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдореЗрдВ рдПрдХ рдкреИрд░рд╛рдореАрдЯрд░ рд╣реЛрдЧрд╛ - рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд C ++ - рд╡рд╣ рдкреНрд░рдХрд╛рд░ рдЬрд┐рд╕рдореЗрдВ рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреЛ рдЪрд╛рд▓реВ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдЧрд╛, рдФрд░ ActionScript рдХреА рдУрд░ рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдирд╛рдо рдХрд╛ рднреА рдкрддрд╛ рд▓рдЧрд╛рдирд╛ рд╣реЛрдЧрд╛ред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП:

 Type<short>::convert(L"20"); //  20,  short Type<short>::name(); // short  ActionScript  "number"
      
      





рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛрдб Type



:

 template<typename CppType> struct Type : std::enable_if< !std::is_array<CppType>::value, TypeHelper< typename std::decay<CppType>::type> >::type { }; template<typename CppType> struct Type<CppType*> { };
      
      





рдпрд╣рд╛рдБ рд╣рдо рдЗрд╕ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЗ рд▓рд╛рдкрд░рд╡рд╛рд╣ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдиреНрдпреВрдирддрдо рд╕рд╛рд╡рдзрд╛рдирд┐рдпрд╛рдБ рджреЗрдЦрддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдк рдЗрд╕ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЛ рдХрд┐рд╕реА рдкреНрд░рдХрд╛рд░ рдХреЗ рдкреЙрдЗрдВрдЯрд░ рд╕реЗ рдЗрдВрд╕реНрдЯреЗрдВрдЯ рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗ, рдХреНрдпреЛрдВрдХрд┐ рд╣рдо рдкреЙрдЗрдВрдЯрд░реНрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ (рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдПрдХреНрд╢рдирд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд▓рд┐рдП , рдмрд╕ рдХреЛрдИ рдкреЙрдЗрдВрдЯрд░реНрд╕ рдирд╣реАрдВ рд╣реИрдВ)ред рдмреЗрд╢рдХ, рд╕рднреА рд╕рд╛рд╡рдзрд╛рдирд┐рдпрд╛рдВ рдирд╣реАрдВ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЙрдиреНрд╣реЗрдВ рдЖрд╕рд╛рдиреА рд╕реЗ рдЬреЛрдбрд╝рд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рдореБрдЦреНрдп рд░реЛрдмреЛрдЯ рдХреЛ рдЕрдиреНрдп TypeHelper



рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреНрд▓рд╛рд╕ рджреНрд╡рд╛рд░рд╛ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред TypeHelper



рдПрдХ рдирдВрдЧреЗ рдкреНрд░рдХрд╛рд░ рд╕реЗ TypeHelper



рд╣реИред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, const std::wstring&



std::wstring



, рдЗрддреНрдпрд╛рджрд┐ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддреЗ рд╣реИрдВ рдпрд╣ рдХреНрд╖рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдФрд░ рдпрд╣ рдЙрди рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдмреАрдЪ рдХреЗ рдЕрдВрддрд░ рдХреЛ рджреВрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдЬрд┐рдирдореЗрдВ рдЯрд╛рдЗрдк f(const std::wstring&)



рдФрд░ f(std::wstring)



рд╣рд╕реНрддрд╛рдХреНрд╖рд░ рд╣реЛрддреЗ рд╣реИрдВред рд╣рдо рд╕рд░рдгрд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП рдХреБрдЫ рдПрд╣рддрд┐рдпрд╛рдд рднреА рдХрд░рддреЗ рд╣реИрдВ, рдХреНрдпреЛрдВрдХрд┐ рдЗрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ рдЖрдЬреНрдЮрд╛рдХрд╛рд░реА decay



рд░реЛрдмреЛрдЯ рдХреЗ рд╕рд╛рде рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рдХрд╛рдо рдХрд░реЗрдЧрд╛ рдФрд░ рд╣рдореЗрдВ рд╡реИрд╕рд╛ рдирд╣реАрдВ рдорд┐рд▓реЗрдЧрд╛ рдЬреИрд╕рд╛ рд╣рдо рдЪрд╛рд╣рддреЗ рдереЗред



рдореБрдЦреНрдп TypeHelper



рдЯреЗрдореНрдкрд▓реЗрдЯред рдпрд╣ рд╕рдВрдЦреНрдпрд╛рдУрдВ рдХреЛ рдмрджрд▓рдиреЗ рдХрд╛ рдХрд╛рдо рдХрд░реЗрдЧрд╛ред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рдЕрдВрдХрдЧрдгрд┐рдд рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЗ рд▓рд┐рдП рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░реЗрдЧрд╛, рд╣рд╛рд▓рд╛рдВрдХрд┐, рдПрдХ рдЕрдЪреНрдЫреЗ рддрд░реАрдХреЗ рд╕реЗ, рд╕рднреА рд╡рд░реНрдг рдкреНрд░рдХрд╛рд░реЛрдВ рдХреЛ рдмрд╛рд╣рд░ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реЛрдЧрд╛ (рдпрд╣ std::is_same



рд╕рд╛рде is_valid_type



рдХреЛ рдереЛрдбрд╝рд╛ рд╕рдВрд╢реЛрдзрд┐рдд рдХрд░рдХреЗ рдХрд░рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реИ)ред

TypeHelper
 template<typename CppType> struct TypeHelper { private: enum { is_valid_type = std::is_arithmetic<CppType>::value }; public: typedef typename std::enable_if<is_valid_type, CppType>::type Type; static typename std::enable_if<is_valid_type, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType static Type convert(const std::wstring& str) { double value = std::stod(str); return static_cast<Type>(value); } };
      
      







рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╕рднреА рдкреНрд░рдХрд╛рд░ рдХреЗ рдирд╛рдо, ActionScript рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ , рд╕рдВрдЦреНрдпрд╛ рд╣реИ ред рдПрдХ рд╕реНрдЯреНрд░рд┐рдВрдЧ рд╕реЗ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкрд╣рд▓реЗ рд╕рд╛рд╡рдзрд╛рдиреА рд╕реЗ double



рдХрдирд╡рд░реНрдЯ рдХрд░реЗрдВ, рдФрд░ рдлрд┐рд░ рд╣рдореЗрдВ рдЬрд┐рд╕ рдкреНрд░рдХрд╛рд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рд╣рдореЗрдВ bool



, std::wstring



рдФрд░ void



рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдЕрдиреНрдп рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреА рднреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

рдЯрд╛рдЗрдк рд╣реЗрд▓реНрдкрд░ рдлреБрд▓ рд╕реНрдкреЗрд╢рд▓рд╛рдЗрдЬреЗрд╢рди рдлреЙрд░ рдмреВрд▓, рдПрд╕рдЯреАрдбреА :: рд╡реЗрд╕реНрдЯреНрд░рд┐рдВрдЧ, рд╢реВрдиреНрдп
 template<> struct TypeHelper<bool> { typedef bool Type; static std::wstring name() { return L"bool"; } static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { return str; } }; template<> struct TypeHelper<void> { typedef void Type; static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { } };
      
      









рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдпрд╣ рд╕рдм рд╣реИ! рдпрд╣ рдмрдбрд╝реЗ рдХрд░реАрдиреЗ рд╕реЗ рд╕рдм рдХреБрдЫ рдПрдХ рд╕рд╛рде рд░рдЦрддрд╛ рд╣реИред рдЪреВрдВрдХрд┐ рд╣рдореЗрдВ рд╕рдВрдмрдВрдзрд┐рдд рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рд╣реИрдВрдбрд▓рд░ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╕реБрд╡рд┐рдзрд╛рдЬрдирдХ рддрдВрддреНрд░ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ (рдХрдВрдЯреЗрдирд░ рдореЗрдВ рд╕рднреА рд╣реИрдВрдбрд▓рд░ рдХреЛ рд╕реНрдЯреЛрд░ рдХрд░рдирд╛, рдЗрддреНрдпрд╛рджрд┐), рд╣рдо IFunction



рдЗрдВрдЯрд░рдлрд╝реЗрд╕ IFunction



:

 struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } };
      
      





рд▓реЗрдХрд┐рди рдЙрддреНрддрд░рд╛рдзрд┐рдХрд╛рд░реА рд╡рд░реНрдЧреЛрдВ рдХреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдкрддрд╛ рд╣реЛрдЧрд╛ рдХрд┐ рдХрд┐рд╕реА рд╡рд┐рд╢реЗрд╖ рдорд╛рдорд▓реЗ рдХреЗ рд▓рд┐рдП рдХрд┐рд╕ рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдмреБрд▓рд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдлрд┐рд░ рд╕реЗ рдЯреЗрдореНрдкрд▓реЗрдЯ:

 template<typename ReturnType, typename... Args> struct Function : public IFunction { Function(const std::wstring& function_name, ReturnType (*f)(Args...)) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { if(name_ != parser.function_name()) return false; const auto ArgsCount = sizeof...(Args); if(ArgsCount != parser.arguments_count()) return false; auto indexes = typename generate_sequence<ArgsCount>::type(); auto args = parser.arguments(); if(!validate_types(args, indexes)) return false; return call(args, indexes); } private: template<int... S> bool validate_types(const InvokeParser::ArgsContainer& args, sequence<S...>) { std::array<std::wstring, sizeof...(Args)> cpp_types = { Type<Args>::name()... }; std::array<std::wstring, sizeof...(S)> as3_types = { args[S].first... }; return (cpp_types == as3_types); } template<int... S> bool call(const InvokeParser::ArgsContainer& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } protected: std::function<ReturnType (Args...)> f_; std::wstring name_; }; template<typename ReturnType, typename... Args> std::shared_ptr<IFunction> make_function(const std::wstring& as3_function_name, ReturnType (*f)(Args...)) { return std::make_shared<Function<ReturnType, Args...>>(as3_function_name, f); }
      
      







рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдореИрдВ рдЖрдкрдХреЛ рджрд┐рдЦрд╛рдКрдВрдЧрд╛ рдХрд┐ рдХреИрд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рд╣реИ:

 void test_handler(const std::wstring& str, bool flag, double n) { std::wcout << L"test: " << str << L", " << std::boolalpha << flag << ", " << n << std::endl; } int main() { as3::InvokeParser parser; std::wstring str = L"<invoke name=\"test\" returntype=\"xml\">" L"<arguments><string>str</string><false/><number>1.0</number></arguments>" L"</invoke>"; if(parser.parse(str)) { auto function = as3::make_function(L"test", test_handler); function->call(parser); } }
      
      





рдЪрд▓рд┐рдП рдбрд┐рдЯреЗрд▓реНрд╕ рдкрд░ рдЪрд▓рддреЗ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдПрдХ рд╕рд╣рд╛рдпрдХ рдлрд╝рдВрдХреНрд╢рди рд╣реИ as3::make_function()



, рдЬреЛ рдХреЙрд▓рдмреИрдХ рдХреЗ рдкреНрд░рдХрд╛рд░ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд╣реАрдВ рд╕реЛрдЪрдиреЗ рдореЗрдВ рдорджрдж рдХрд░рддрд╛ рд╣реИред

рджреВрд╕рд░реЗ, рдЪрд▓рдиреЗ рдХреЗ рд▓рд┐рдП (рдЕрдзрд┐рдХ рд╕рд╣реА рдврдВрдЧ рд╕реЗ, "рдкреИрдЯрд░реНрди" рдХреЛ рдЕрдирдкреИрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкреИрд░рд╛рдореАрдЯрд░ рдкреИрдХреЗрдЬ рдХреЗ рд▓рд┐рдП рдкреИрд░рд╛рдореАрдЯрд░ рдкреИрдХ рд▓рд┐рдВрдХ (рдиреАрдЪреЗ) рджреЗрдЦреЗрдВ) (рдЕрдиреБрд╡рд╛рдж рдХреИрд╕реЗ рдХрд░реЗрдВ? рдкреИрд░рд╛рдореАрдЯрд░ рдкреИрдХ ), рд╕рд╣рд╛рдпрдХ рд╕рдВрд░рдЪрдирд╛рдУрдВ sequence



рдФрд░ generate_sequence



:

 template<size_t N, size_t... Sequence> struct generate_sequence : generate_sequence<N - 1, N - 1, Sequence...> { }; template<size_t...> struct sequence { }; template<int... Sequence> struct generate_sequence<0, Sequence...> { typedef sequence<Sequence...> type; };
      
      





рд╕реНрдЯреИрдХрдУрд╡рд░рдлрд╝реНрд▓реЛ рдкрд░ рдЬрд╛рд╕реВрд╕ред

рд╕рдВрдХреНрд╖реЗрдк рдореЗрдВ, generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




 generate_sequence    0, 1, 2, ... N - 1
      
      



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




 generate_sequence    0, 1, 2, ... N - 1
      
      



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))

!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.








generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




 generate_sequence    0, 1, 2, ... N - 1
      
      



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




 generate_sequence    0, 1, 2, ... N - 1
      
      



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




 generate_sequence    0, 1, 2, ... N - 1
      
      



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




 generate_sequence    0, 1, 2, ... N - 1
      
      



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.




generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

template<typename... Args> struct Test { template<int... S> static bool test(const std::vector<pair<int, float>>& args, sequence<S...>) { f_(Type<Args>::convert(args[S].second)...); return true; } }; // - test(args, typename generate_sequence<sizeof...(Args)>::type())





test



Args = <int, float>



:

f_(Type<int>::convert(args[0].second), Type<float>::convert(args[1].second))





!

- Function::validate_types



. C++ - ActionScript- , - , . - ! . !

- call(const InvokeParser::ArgsContainer& args, sequence<S...>)



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



InvokeParser class InvokeParser { public: typedef std::vector<std::pair<std::wstring, std::wstring> > ArgsContainer; typedef ArgsContainer::value_type TypeValuePair; public: InvokeParser() : invoke_name_() , arguments_() { } bool parse(const std::wstring& str) { using namespace boost; using namespace boost::property_tree; try { std::wistringstream stream(str); wptree xml; read_xml(stream, xml); optional<wptree&> invoke_attribs = xml.get_child_optional(L"invoke.<xmlattr>"); optional<wptree&> arguments_xml = xml.get_child_optional(L"invoke.arguments"); if(!invoke_attribs || !arguments_xml) return false; optional<std::wstring> name = invoke_attribs->get_optional<std::wstring>(L"name"); if(!name) return false; invoke_name_ = *name; arguments_.reserve(arguments_xml->size()); for(wptree::const_iterator arg_value_pair = arguments_xml->begin(), end = arguments_xml->end(); arg_value_pair != end; ++arg_value_pair) { std::wstring arg_type = arg_value_pair->first; std::wstring arg_value = arg_value_pair->second.get_value(L""); if((arg_type == L"true") || (arg_type == L"false")) { arg_value = arg_type; arg_type = L"bool"; } arguments_.push_back(TypeValuePair(arg_type, arg_value)); } return true; } catch(const boost::property_tree::xml_parser_error& /*parse_exc*/) { } catch(...) { } return false; } std::wstring function_name() const { return invoke_name_; } size_t arguments_count() const { return arguments_.size(); } const ArgsContainer& arguments() const { return arguments_; } private: std::wstring invoke_name_; ArgsContainer arguments_; };







TypeHelper template<typename CppType> struct TypeHelper { private: // Arithmetic types are http://en.cppreference.com/w/cpp/language/types. // Need to exclude 'Character types' from this list // (For 'Boolean type' this template has full specialization) typedef boost::mpl::and_< boost::is_arithmetic<CppType>, boost::mpl::not_<boost::is_same<CppType, char> >, boost::mpl::not_<boost::is_same<CppType, wchar_t> >, boost::mpl::not_<boost::is_same<CppType, unsigned char> >, boost::mpl::not_<boost::is_same<CppType, signed char> > > ValidCppType; public: // We can get C++ type name equivalent for AS3 "number" type only if // C++ type @CppType is @ValidCppType(see above) typedef typename boost::enable_if< ValidCppType, CppType>::type Type; // Get AS3 type name for given @CppType(see @ValidCppType) static typename boost::enable_if< ValidCppType, std::wstring>::type name() { return L"number"; } // Convert AS3 number type from string to @CppType(see @ValidCppType) static Type convert(const std::wstring& str) { double value = from_string<wchar_t, double>(str); // TODO: Use boost type cast return static_cast<Type>(value); } }; template<> struct TypeHelper<bool> { typedef bool Type; // AS3 type name for boolean type static std::wstring name() { return L"bool"; } // Convert AS3 boolean value from string to our bool static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { // Ok, do nothing return str; } }; template<> struct TypeHelper<void> { typedef void Type; // AS3 type name for void type.. static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { // Oops.. ASSERT_MESSAGE(false, "Can't convert from sring to void"); } }; // @TypeHelper provides implementation // only for "number" type(arithmetic, without characters type), bool, string and void. // For any other type @TypeHelper will be empty. // decay is used for removing cv-qualifier. But it's not what we want for arrays. // That's why using enable_if template<typename CppType> struct FlashType : boost::enable_if< boost::mpl::not_< boost::is_array<CppType> >, TypeHelper< typename std::tr1::decay<CppType>::type> >::type { }; // Partial specialization for pointers // There is no conversion from AS3 type to C++ pointer.. template<typename CppType> struct FlashType<CppType*> { // static assert };









, - FunctionCaller



- .... :

FunctionCaller template<int N> struct FunctionCaller { template<typename Function> static bool call(Function /*f*/, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { ASSERT_MESSAGE_AND_RETURN_VALUE( false, "Provide full FunctionCaller specialization for given arguments count", false); } }; template<> struct FunctionCaller<0> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& /*args*/ #if defined(DEBUG) , const std::wstring& /*dbg_function_name*/ #endif ) { // Call function without args f(); return true; } }; template<> struct FunctionCaller<1> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; const InvokeParser::TypeValuePair& arg = args[0]; if(Arg1::name() != arg.first) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 1 arg f(Arg1::convert(arg.second)); return true; } }; template<> struct FunctionCaller<2> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 2 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second)); return true; } }; template<> struct FunctionCaller<3> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 3 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second)); return true; } }; template<> struct FunctionCaller<4> { template<typename Function> static bool call(Function f, const InvokeParser::ArgsContainer& args #if defined(DEBUG) , const std::wstring& dbg_function_name #endif ) { typedef FlashType<typename boost::function_traits<Function>::arg1_type> Arg1; typedef FlashType<typename boost::function_traits<Function>::arg2_type> Arg2; typedef FlashType<typename boost::function_traits<Function>::arg3_type> Arg3; typedef FlashType<typename boost::function_traits<Function>::arg4_type> Arg4; const InvokeParser::TypeValuePair& arg1 = args[0]; const InvokeParser::TypeValuePair& arg2 = args[1]; const InvokeParser::TypeValuePair& arg3 = args[2]; const InvokeParser::TypeValuePair& arg4 = args[3]; if((Arg1::name() != arg1.first) || (Arg2::name() != arg2.first) || (Arg3::name() != arg3.first) || (Arg4::name() != arg4.first)) { #if defined(DEBUG) ::OutputDebugStringW(Sprintf<wchar_t>( L"Function: \"%s\":\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n" L"%s -> %s\n", dbg_function_name.c_str(), Arg1::name().c_str(), arg1.first.c_str(), Arg2::name().c_str(), arg2.first.c_str(), Arg3::name().c_str(), arg3.first.c_str(), Arg4::name().c_str(), arg4.first.c_str()).c_str()); #endif ASSERT_MESSAGE_AND_RETURN_VALUE(false, "Type mismatch", false); } // Call function with 4 args f(Arg1::convert(arg1.second), Arg2::convert(arg2.second), Arg3::convert(arg3.second), Arg4::convert(arg4.second)); return true; } };









Function



:

Function struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; template<typename FunctionPointer> struct Function : public IFunction { Function(const std::wstring& function_name, FunctionPointer f) : f_(f) , name_(function_name) { } bool call(const InvokeParser& parser) { typedef typename boost::remove_pointer<FunctionPointer>::type FunctionType; enum { ArgsCount = boost::function_traits<FunctionType>::arity }; ASSERT_MESSAGE_AND_RETURN_VALUE( name_ == parser.function_name(), "Incorrect function name", false); ASSERT_MESSAGE_AND_RETURN_VALUE( ArgsCount == parser.arguments_count(), "Incorrect function arguments count", false); return FunctionCaller<ArgsCount>::template call<FunctionType>( f_, parser.arguments() #if defined(DEBUG) , name_ #endif ); } protected: FunctionPointer f_; std::wstring name_; }; template<typename FunctionPointer> IFunction* CreateFunction(const std::wstring& name, FunctionPointer f) { return new Function<FunctionPointer>(name, f); }









!



UPD: - , , 14 () std::make_index_sequence , , generate_sequence



.







All Articles