特定の文字列に対応する関数を呼び出す

こんにちは

記事にもっと正確な名前を付ける方法は知りませんでしたが、次のような小さなパズルを1つ解析したいと思います。

入力は何らかの方法でフォーマットされた文字列であり、関数の名前、引数、および引数のタイプが示されます。 適切な関数ハンドラーを呼び出して、すべての引数を正しく渡すことができる必要があります。


たとえば、 ActionScriptは3つの引数strfalse1.0 (それぞれ、引数のタイプ: StringBooleanNumber )でテスト関数を呼び出そうとします。

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





C ++で対応する関数を呼び出すようにしたい:

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







カットの下-新しい標準を使用した実装、および比較のために、古い標準(およびブーストの液滴)を使用した実装。



始めましょう。 まず、何らかの方法で文字列を解析する必要があります。 これは問題の本質ではないため、xmlの解析にはBoost.PropertyTreeを使用します関数名前引数type-its valueのペアの配列を格納する補助クラスInvokeParser



でこれらすべてを非表示にします

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









次に、テンプレートクラスType



を作成します。このクラスには、1つのパラメーター(特定のC ++)があります。このクラスでは、文字列を変換し、ActionScript側から対応する名前を見つけます。 例:

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





Type



テンプレートコード:

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





ここでは、このテンプレートの不注意なユーザーに対する最小限の注意事項を示します。たとえば、ポインターを使用しないため( ActionScriptには特にポインターがないため)、あるタイプへのポインターでこのテンプレートをインスタンス化することはできません。 もちろん、すべての予防措置があるわけではありませんが、簡単に追加できます。

ご覧のとおり、メインロボットは別のTypeHelper



テンプレートクラスによって実行されます。 TypeHelper



、ベアタイプによってインスタンス化されます。 たとえば、 const std::wstring&



std::wstring



などconst std::wstring&



取得されconst std::wstring&



。 これはdecayを使用して行われます。 そして、これは、タイプf(const std::wstring&)



f(std::wstring)



シグネチャを持つ関数の違いを取り除くために行われます。 この場合、従順なdecay



はロボットで素晴らしい仕事をし、私たちが望んでいたものを正確に得られないので、配列にもいくつかの予防策を行います。



メインのTypeHelper



テンプレート。 数値の変換に役立ちます。 私たちの場合、 算術型に対しては完全に機能しますが、良い方法では、すべての文字型を除外する必要があります(これは、 is_valid_type



std::is_same



でわずかに変更することで難しくありません)。

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







ご覧のとおり、 ActionScriptの場合、すべての数値型の名前はnumberです。 文字列から変換するには、最初に慎重にdouble



に変換してから、必要な型に変換します。

bool



std::wstring



およびvoid



型には他の処理も必要です。

bool、std :: Typeヘルパー、wstring、void
 template<> struct TypeHelper<bool> { typedef bool Type; static std::wstring name() { return L"bool"; } static bool convert(const std::wstring& str) { return (str == L"true"); } }; template<> struct TypeHelper<std::wstring> { typedef std::wstring Type; static std::wstring name() { return L"string"; } static std::wstring convert(const std::wstring& str) { return str; } }; template<> struct TypeHelper<void> { typedef void Type; static std::wstring name() { return L"undefined"; } static void convert(const std::wstring& /*str*/) { } };
      
      









実際、それだけです! すべてをきちんとまとめることが残っています。 対応する関数のハンドラーを作成する便利なメカニズムが必要なので(コンテナーにすべてのハンドラーを保存するなど)、 IFunction



インターフェイスを作成します。

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





ただし、後継クラスは、特定のケースでどの関数を呼び出す必要があるかをすでに知っています。 もう一度テンプレート:

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







最初に、使用方法を示します。

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





詳細に移りましょう。 まず、ヘルパー関数as3::make_function()



があります。これは、渡されるコールバックのタイプについて考えないようにするのに役立ちます。

第二に、パラメータパッケージ(翻訳方法? パラメータパック )の歩行(より正確には、「パターン」を解凍し、 パラメータパックリンク(下記)を参照)するために、補助構造sequence



generate_sequence



ます。

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





stackoverflowをスパイします。

簡単に言えば、 generate_sequence 0, 1, 2, ... N - 1



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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

!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.








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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.




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



, (: " ") sequence



. Pack expansion ( " ").

:

typename... Args



f



. f



, , f



:

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





test



Args = <int, float>



:

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





!

- Function::validate_types



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

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



, , .

- make_function()



, IFunction



, ( ) .



, , boost::function_traits



mpl



:)



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







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









, - FunctionCaller



- .... :

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









Function



:

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









!



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



.







All Articles