📜 ⬆️ ⬇️

Calling the function corresponding to the specified string

Hello!
I did not know how to name the article more precisely, but I would like to make out one small puzzle, which sounds like this:
The input is a formatted string in which the name of the function, its arguments and the types of the arguments are indicated. You need to be able to call the appropriate function handler, passing all arguments correctly.

For example, so ActionScript tries to call the test function with three arguments str , false , 1.0 (respectively, the types of arguments: String , Boolean , Number ):
<invoke name="test" returntype="xml"><arguments><string>str</string><false/><number>1.0</number></arguments></invoke> 

I would like the corresponding function to be called from C ++:
 void test_handler(const std::wstring& str, bool flag, double n); 


Under the cut - the implementation using the new standard and, for comparison, the implementation using the old standard (and droplets of boost-a).

Let's get started First you need to somehow parse the string. Since this is not the essence of the task, we will use Boost.PropertyTree to parse the xml. We'll hide all this in the help class InvokeParser , which will store the name of the function and an array of pairs of argument type — its value :
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 



Now we’ll write a generic Type class that will have one parameter — some C ++ — the type into which you will need to turn the string, as well as learn the corresponding name from ActionScript. For example:
 Type<short>::convert(L"20"); //  20,  short Type<short>::name(); // short  ActionScript  "number" 

Template Type Code:
 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*> { }; 

Here we see the minimum precautions for the reckless user of this template, for example, you cannot instantiate this template with a pointer to some type, since we do not use pointers (specifically for ActionScript , there are simply no pointers). Of course, not all precautions are here, but you can easily add them.
As you can see, the main robot is performed by another TypeHelper class. TypeHelper instantiated by the “naked” type. For example, for const std::wstring& get std::wstring , etc. This is done using decay . And this is done in order to remove the differences between functions that have signatures of type f(const std::wstring&) and f(std::wstring) . We also do some precaution for arrays, as in this case, an obedient decay will cope well with the robot and we will get not exactly what we wanted.
')
The main template TypeHelper . It will serve to convert numbers. In our case, it will work fine for Arithmetic types, although, in an amicable way, you would need to exclude all character types (it is not difficult to do this by slightly modifying is_valid_type with std::is_same ).
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); } }; 


As you can see, the name of all numeric types, in the case of ActionScript - number . To convert from a string, first accurately convert to double , and then to the type we need.
We also need other processing for the bool , std::wstring and void types:
Full TypeHelper specializations for 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*/) { } }; 



That's all, in fact! It remains to carefully put everything together. Since you need to have a convenient mechanism for creating handlers for the corresponding functions (storing all the handlers in a container, etc.), let's create an IFunction interface:
 struct IFunction { virtual bool call(const InvokeParser& parser) = 0; virtual ~IFunction() { } }; 

But the heir classes will already know what function to call for a particular case. Again the pattern:
 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); } 


First show how to use:
 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); } } 

We turn to the details. First, there is an auxiliary function as3::make_function() , which helps not to think about the type of callback passed.
Secondly, in order to go through (more correctly, unpack the “pattern”, look at the Parameter pack link (below)) in the parameter package (how to translate? Parameter pack ), the auxiliary structures sequence and 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; }; 

Peeped on stackoverflow .
In a nutshell, 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 .

Source: https://habr.com/ru/post/223865/


All Articles