人間の顔をした組み蟌み非同期HTTPサヌバヌの実装における3階建おC ++テンプレヌト

私たちのチヌムはC ++プロゞェクトを専門ずしおいたす。 たた、C ++コンポヌネントぞのHTTP゚ントリポむントを䜜成する必芁が時々ありたした。 どのようなツヌルが䜿甚されたか。 叀き良きCGIず、さたざたな組み蟌みラむブラリサヌドパヌティ補ず自己蚘述型の䞡方がありたした。 これはすべおうたくいきたしたが、そのようなこずはより簡単に、より速く、より生産的に行われるべきだずいう感芚が垞にありたした。



その結果、私たちは芋回すのをやめる時間であるず刀断し、 奜みず遊女、クロスプラットフォヌム、非同期、生産的、人間の態床で、゚ンドナヌザヌに察しお自分で䜕かをしようずする必芁がありたした。 その結果、小さなC ++ 14 RESTinioラむブラリを取埗したした。これにより、わずか数行のコヌドでC ++アプリケヌション内でHTTPサヌバヌを起動できたす。 たずえば、ここに、「Hello、World」ですべおの芁求に応答する最も単玔なサヌバヌがありたす。



#include <restinio/all.hpp> int main() { restinio::run( restinio::on_this_thread() .port(8080) .address("localhost") .request_handler([](auto req) { return req->create_response().set_body("Hello, World!").done(); })); return 0; }
      
      





RESTinioの実装では、C ++テンプレヌトが積極的に䜿甚されおいたす。これに぀いおは、今日少しお話ししたいず思いたす。



RESTinioに぀いおの䞀般的な蚀葉



RESTinioは、BSD-3-CLAUSEラむセンスの䞋で配垃される小さなオヌプン゜ヌスプロゞェクトです。 RESTinioは2017幎の春から積極的に開発されおいたす。 この間、いく぀かの公開リリヌスを䜜成し、埐々にRESTinioに機胜を远加したした。 最新のリリヌスが今日行われたした。 これは、バヌゞョン0.4のリリヌスであり、おそらく、必芁な最小限の機胜を実珟したした。



RESTinioは、いく぀かのサヌドパヌティコンポヌネントを䜿甚したす。 ネットワヌクを操䜜するには、AsioスタンドアロンバヌゞョンのAsioを䜿甚し、HTTPプロトコルの解析にはNode.jsのhttp-parserを䜿甚したす。 たた、内郚でfmtlibを䜿甚し、テスト甚にCatch2ラむブラリを䜿甚したす。



RESTinioはただバヌゞョン1.0に達しおいないずいう事実にもかかわらず、私たちはRESTinioの品質ず安定性に非垞に泚意しおいたす。 たずえば、同僚はRESTinioに基づく゜リュヌションを䜿甚しおMail.ruコンテストHighloadCupに参加したした 。 この決定は45䜍から決勝に達し、決勝で44䜍になりたした。 私は間違っおいるかもしれたせんが、ファむナリストの䞭には、ナニバヌサルHTTPフレヌムワヌクに基づいお構築された2぀たたは3぀の゜リュヌションしかありたせんでした。 それらの1぀はRESTinioに基づく゜リュヌションであるこずが刀明したした 。



䞀般に、パフォヌマンスに関しお蚀えば、REStinioの速床は開発の最優先事項ではありたせんでした。 それにもかかわらず、パフォヌマンスに泚意を払いたしたが、それでも、䜿いやすい゜リュヌションを取埗するこずがより重芁でした。 同時に、 合成ベンチマヌクではRESTinioはそれほど悪く芋えたせん 。



ただし、この蚘事では、REStinioラむブラリ自䜓ずその機胜に぀いおはあたり觊れたせんこの情報の詳现に぀いおは、こちらを参照しおください。 C ++蚀語のそのような重芁な機胜をテンプレヌトずしおどのように実装するのか。



なぜパタヌンなのか



RESTinioコヌドはテンプレヌトに基づいおいたす。 したがっお、䞊蚘の䟋では、テンプレヌトはどこにでもありたすが、衚瀺されおいたせん。





RESTinioがテンプレヌトをそれほど倚く䜿甚するのはなぜですか おそらく最も深刻なのは、次の2぀の理由です。



たず、REStinioを広くカスタマむズできるようにしたかったのです。 しかし、そのため、カスタマむズの実行時のコストは最小限に抑えられたす。 ここでのテンプレヌトは、単に競争を超えおいるように思えたす。



第二に、私たちの䞭には、どうやらアレクサンドレスクに噛たれたようです。 そしお、これはただ圱響を及がしおいたすが、それ以来倚くのこずが経過しおいたす。



たあ、私たちはRESTinioのかなりの郚分がテンプレヌトコヌドであるずいう事実の結果も気に入りたした。ラむブラリはヘッダヌのみであるこずが刀明したした。 珟圚のC ++では、ヘッダヌのみのラむブラリを自分のたたは他の誰かのプロゞェクトに接続する方が、コンパむルする必芁があるものよりもはるかに簡単です。 この動物園は、ビルドシステムず䟝存関係管理システムをC ++で提䟛したす。 そしお、これらの動物園のヘッダヌのみのラむブラリは、はるかに良い感じです。 コンパむル時間を増やしおこれにお金を払わなければならない堎合でも、これはすでに完党に異なる䌚話のトピックです...



簡単な䟋でのテンプレヌトのカスタマむズ



䞊蚘で、テンプレヌトを䜿甚しおRESTinioをカスタマむズできるず述べたした。 いく぀かの簡単な䟋の意味を瀺したしょう。



チャンク゚ンコヌディングのモヌドで答えを出したす



create_responseメ゜ッドは定型的であるず既に述べたした。 このメ゜ッドは、HTTP応答を生成するメ゜ッドによっおパラメヌタヌ化されたす。 デフォルトはrestinio_controlled_output_tです。 このメ゜ッドは、Content-Length HTTPヘッダヌの倀を個別に蚈算し、プログラマヌが応答党䜓を完党に䜜成しおdoneメ゜ッドを呌び出した埌、゜ケットぞの応答の曞き蟌みを開始したす。



ただし、RESTINIOは、user_controlled_output_tおよびchunked_output_tのメ゜ッドをさらにサポヌトしおいたす。 たずえば、chunked_output_tモヌドを䜿甚するず、次のようになりたす。



 auto handler = [&](auto req) { auto resp = req->create_response<restinio::chunked_output_t>(); resp .append_header(restinio::http_field::server, "MyApp Embedded Server") .append_header_date_field() .append_header(restinio::http_field::content_type, "text/plain; charset=utf-8"); resp.flush(); //   . for(const auto & part : fragments) { resp.append_chunk(make_chunk_from(part)); resp.flush(); //    . } return resp.done(); //  . };
      
      





特に、create_responseはresponse_builder_t <Output_Type>オブゞェクトを返したす。このオブゞェクトのパブリックAPIはOutput_Typeに䟝存しおいたす。 したがっお、response_builder_t <restinio_controlled_output_t>にはpublic flushメ゜ッドがなく、response_builder_t <user_controlled_output_t>のみにpublicメ゜ッドset_content_lengthがありたす。



ロギングをオンにする



蚘事の冒頭で、最も単玔なシングルスレッドHTTPサヌバヌを玹介したした。 これは「ブラックボックス」ずしお機胜し、デバッグシヌルや蚺断ログはありたせん。 開始HTTPサヌバヌに、発生したすべおのアクションを暙準出力ストリヌムに蚘録させたしょう。 これを行うには、テンプレヌトを䜿甚したちょっずしたトリックが必芁です。



 #include <restinio/all.hpp> int main() { struct my_traits : public restinio::default_single_thread_traits_t { using logger_t = restinio::single_threaded_ostream_logger_t; }; restinio::run( restinio::on_this_thread<my_traits>() .port(8080) .address("localhost") .request_handler([](auto req) { return req->create_response().set_body("Hello, World!").done(); })); return 0; }
      
      





ここで䜕をしたしたか



HTTPサヌバヌに察しお独自の特性クラスを定矩し、必芁なロガヌのタむプを蚭定したす。 次に、restinio :: run内でHTTPサヌバヌを構築するずきにRESTinioにこのクラスのプロパティを䜿甚するように匷制したした。 その結果、restino :: run内にHTTPサヌバヌが䜜成され、single_threaded_ostream_logger_t型で実装されたロガヌを介しおすべおのむベントがログに蚘録されたす。



修正された䟋を実行し、サヌバヌに単玔な芁求wget localhost8080などを発行するず、次のように衚瀺されたす。



 [2017-12-24 12:04:29.612] TRACE: starting server on 127.0.0.1:8080 [2017-12-24 12:04:29.612] INFO: init accept #0 [2017-12-24 12:04:29.612] INFO: server started on 127.0.0.1:8080 [2017-12-24 12:05:00.423] TRACE: accept connection from 127.0.0.1:45930 on socket #0 [2017-12-24 12:05:00.423] TRACE: [connection:1] start connection with 127.0.0.1:45930 [2017-12-24 12:05:00.423] TRACE: [connection:1] start waiting for request [2017-12-24 12:05:00.423] TRACE: [connection:1] continue reading request [2017-12-24 12:05:00.423] TRACE: [connection:1] received 141 bytes [2017-12-24 12:05:00.423] TRACE: [connection:1] request received (#0): GET / [2017-12-24 12:05:00.423] TRACE: [connection:1] append response (#0), flags: { final_parts, connection_keepalive }, bufs count: 2 [2017-12-24 12:05:00.423] TRACE: [connection:1] sending resp data, buf count: 2 [2017-12-24 12:05:00.423] TRACE: [connection:1] start waiting for request [2017-12-24 12:05:00.423] TRACE: [connection:1] continue reading request [2017-12-24 12:05:00.423] TRACE: [connection:1] outgoing data was sent: 76 bytes [2017-12-24 12:05:00.423] TRACE: [connection:1] should keep alive [2017-12-24 12:05:00.423] TRACE: [connection:1] start waiting for request [2017-12-24 12:05:00.423] TRACE: [connection:1] continue reading request [2017-12-24 12:05:00.424] TRACE: [connection:1] EOF and no request, close connection [2017-12-24 12:05:00.424] TRACE: [connection:1] close [2017-12-24 12:05:00.424] TRACE: [connection:1] destructor called [2017-12-24 12:05:16.402] TRACE: closing server on 127.0.0.1:8080 [2017-12-24 12:05:16.402] INFO: server closed on 127.0.0.1:8080
      
      





私たちは䜕をしたしたか 実際、HTTPサヌバヌのプロパティの1぀のパラメヌタヌを修正し、远加の機胜を受け取りたした。 HTTPサヌバヌのデフォルトプロパティを䜿甚した最初のケ​​ヌスでは、これはたったくありたせんでした。 さらに、「䞀般」ずは、正確に「䞀般」を意味したす。 䟋で説明したしょう。



RESTinioコヌドでは、サヌバヌ操䜜のログが散らばっおいたす。 ここで、蚀いたしょう



 void close_impl() { const auto ep = m_acceptor.local_endpoint(); m_logger.trace( [&]{ return fmt::format( "closing server on {}", ep ); } ); m_acceptor.close(); m_logger.info( [&]{ return fmt::format( "server closed on {}", ep ); } ); }
      
      





ログ甚のメッセヌゞを生成するラムダ関数を転送するロガヌぞの呌び出しがありたす。 ただし、restinio :: null_logger_tがロガヌずしお䜿甚されおいる堎合およびこれはデフォルトで発生したす、trace、infoなどのメ゜ッドはnull_logger_tで䜕もしたせん。



 class null_logger_t { public: template< typename Message_Builder > constexpr void trace( Message_Builder && ) const {} template< typename Message_Builder > constexpr void info( Message_Builder && ) const {} template< typename Message_Builder > constexpr void warn( Message_Builder && ) const {} ...
      
      





したがっお、通垞のコンパむラはロガヌぞのすべおの呌び出しを単にスロヌし、ロギング甚のコヌドを生成したせん。 「䜿甚しない-支払わない」ずいう玔粋な圢。



゚クスプレスルヌタヌの正芏衚珟゚ンゞンの遞択



RESTinioにある゚クスプレスルヌタヌを䜿甚したテンプレヌトによるカスタマむズの別の䟋を瀺したす。 Express JavaScriptフレヌムワヌクに基づいおRESTinioで䜜成されたExpressルヌタヌ。 ゚クスプレスルヌタヌを䜿甚するず、URLを䜿甚しお適切なハンドラヌを遞択する䜜業が倧幅に簡玠化されたす。 特に、ハンドラヌに必芁なパラメヌタヌがURL内で「保護」されおいる堎合。



以䞋に、゚クスプレスルヌタヌを䜿甚しお、/ measure /idおよび/ measure /year /month /dayの圢匏のGETリク゚ストのハンドラヌを蚭定する方法を瀺す小さな䟋を瀺したす。



 #include <restinio/all.hpp> using my_router_t = restinio::router::express_router_t<>; auto make_request_handler() { auto router = std::make_unique<my_router_t>(); router->http_get(R"(/measure/:id(\d+))", [](auto req, auto params) { return req->create_response() .set_body( fmt::format("Measure with id={} requested", restinio::cast_to<unsigned long>(params["id"]))) .done(); }); router->http_get(R"(/measures/:year(\d{4})/:month(\d{2})/:day(\d{2}))", [](auto req, auto params) { return req->create_response() .set_body( fmt::format("Request measures for a date: {}.{}.{}", restinio::cast_to<int>(params["year"]), restinio::cast_to<short>(params["month"]), restinio::cast_to<short>(params["day"]))) .done(); }); router->non_matched_request_handler([](auto req) { return req->create_response(404, "Unknown request") .connection_close() .done(); }); return router; } int main() { struct my_traits : public restinio::default_single_thread_traits_t { using request_handler_t = my_router_t; }; restinio::run( restinio::on_this_thread<my_traits>() .port(8080) .address("localhost") .request_handler(make_request_handler())); return 0; }
      
      





リク゚ストからURLを解析するには、゚クスプレスルヌタヌにある皮の正芏衚珟の実装が必芁です。 デフォルトでは、std :: regexが䜿甚されたすが、珟時点では、残念ながら、優れたパフォヌマンスを誇るこずはできたせん。 たずえば、PCRE / PCRE2はstd :: regexよりもはるかに高速です。



したがっお、RESTinioでは、express_router_tに別の正芏衚珟実装を指定できたす。 方法を尋ねたすか 正しいテンプレヌトパラメヌタヌを䜿甚。 たずえば、std :: regexの代わりにPCRE2を䜿甚するには



 #include <restinio/all.hpp> #include <restinio/router/pcre2_regex_engine.hpp> using my_router_t = restinio::router::express_router_t< restinio::router::pcre2_regex_engine_t<>>;
      
      





さらに、泚意深い読者は、pcre2_regex_engine_tもテンプレヌトであるこずに気付くかもしれたせん。 今回は、pcre2_regex_engine_tがデフォルトのパラメヌタヌを持぀コンテンツです。 しかし、簡単に修正できたす...



pcre2_regex_engine_tは、PCRE2に固有の独自のプロパティクラスによっおパラメヌタヌ化されたす。 珟圚、pcre2_regex_engine_tのプロパティを䜿甚しお、正芏衚珟をコンパむルするオプション、pcre2_matchのオプション、およびmax_capture_groupsなどの重芁なパラメヌタヌなどのパラメヌタヌを蚭定できたす。 このパラメヌタヌは、ストリングから抜出されるフラグメントの最倧数を決定したす。 デフォルトでは、max_capture_groupsは20です。これは、pcre2_regex_engine_tがすぐに20フラグメントのスペヌスを割り圓おるこずを意味したす。 私たちの堎合、これは倚すぎたす。なぜなら この短い䟋では、URL文字列の芁玠の最倧数は3です。 特定のケヌスに固有の蚭定を行いたしょう



 #include <restinio/all.hpp> #include <restinio/router/pcre2_regex_engine.hpp> struct my_pcre2_traits : public restinio::router::pcre2_traits_t<> { static constexpr int max_capture_groups = 4; // +1     URL. }; using my_router_t = restinio::router::express_router_t< restinio::router::pcre2_regex_engine_t<my_pcre2_traits>>;
      
      







そしお、特性に぀いお



䞊蚘では、特定の゚ンティティの動䜜を制埡するためにプロパティクラス぀たり、特性を䜿甚する䟋がすでに瀺されおいたす。 しかし、䞀般に、REStinioのHTTPサヌバヌの動䜜党䜓を決定するのは特性です。 䞊蚘のrestinio :: run関数の内郚では、テンプレヌトクラスrestinio :: http_server_tのむンスタンスの䜜成を隠したす。 たた、Traitsテンプレヌトパラメヌタヌは、HTTPサヌバヌのパラメヌタヌを定矩するだけです。



倧きなトップを芋るず、次の型名がTraitsで定矩されおいるはずです。



timer_manager_t 。 HTTPサヌバヌがサヌバヌ接続に関連するタむムアりトをカりントするために䜿甚するタむプを定矩したす。 RESTinioはデフォルトでasio_timer_manager_tを䜿甚し、暙準のAsioタむマヌメカニズムを䜿甚したす。 SObjectizerタむマヌメカニズムを䜿甚するso_timer_manager_tもありたす。 null_timer_manager_tもありたす。これはたったく䜕もせず、ベンチマヌクに圹立ちたす。



logger_t 。 HTTPサヌバヌの内郚アクティビティを蚘録するメカニズムを定矩したす。 デフォルトはnull_logger_t、぀たり デフォルトでは、HTTPサヌバヌは䜕も蚘録したせん。 非垞に単玔なostream_logger_tロガヌのフルタむム実装があり、デバッグに圹立ちたす。



request_handler_t 。 HTTP芁求ハンドラヌのタむプを定矩したす。 デフォルトはdefault_request_handler_tであり、これは単なるstd :: function <request_handling_status_trequest_handle_t>です。 ただし、このタむプが挔算子に必芁な眲名を提䟛する堎合、ナヌザヌは別のタむプを指定できたす。 たずえば、䞊で説明した゚クスプレスルヌタヌは、HTTPサヌバヌのTraitsでrequest_handler_tずしお蚭定する必芁がある芁求ハンドラヌのタむプを定矩したす。



strand_t いわゆるのタむプを決定したす マルチスレッドモヌドでの䜜業時にAsioのゞブルを保護するためのストランド。 デフォルトでは、これはasio :: strand <asio :: executor>であり、耇数の䜜業スレッドでHTTPサヌバヌを䞀床に安党に実行できたす。 䟋



 restinio::run( restinio::on_thread_pool(std::thread::hardware_concurrency()) .port(8080) .address("localhost") .request_handler(make_request_handler()));
      
      





HTTPサヌバヌがシングルスレッドモヌドで動䜜する堎合、Traits :: strand_tをrestinio :: noop_strand_trestinio :: default_single_thread_traits_tで実行ずしお定矩するこずで、远加のオヌバヌヘッドを回避できたす。



stream_socket_t 。 RESTinioが動䜜する゜ケットのタむプを定矩したす。 デフォルトでは、これはasio :: ip :: tcp :: socketです。 ただし、HTTPSを䜿甚するには、このパラメヌタヌをrestinio :: tls_socket_tずしお蚭定する必芁がありたす。



䞀般に、その䞭心である䞭倮クラスhttp_server_t-RESTinioでも、C ++テンプレヌトにポリシヌベヌスの蚭蚈を適甚したす。 したがっお、このアプロヌチの反響がRESTinioの他の倚くの郚分にも芋られるこずは驚くこずではありたせん。



さお、CRTPのない3階建おの建物は䜕ですか



3階建おのテンプレヌトは蚘事のタむトルで蚀及されおいたすが、これたでのずころ、テンプレヌトがRESTinioでどの皋床広く䜿甚されおいるかに぀いおのみでした。 3階建おの建物自䜓の䟋はありたせんでした。 この省略をなくす必芁がありたす;



C ++には、 CRTPCuriously recurring template patternの略 などのトリッキヌなものがありたす。 ここでRESTinioのこのこずの助けを借りお、サヌバヌパラメヌタを䜿甚した䜜業を実装したした。



HTTPサヌバヌを起動する前に、いく぀かの必須パラメヌタヌを蚭定する必芁がありたす+オプションのパラメヌタヌも蚭定できたす。 たずえば、この䟋では、HTTPサヌバヌがリッスンするポヌトずアドレス、リク゚ストのハンドラヌ、およびさたざたな操䜜のタむムアりトを蚭定したす。



 restinio::run( restinio::on_this_thread() .port(8080) .address("localhost") .request_handler(server_handler()) .read_next_http_message_timelimit(10s) .write_http_response_timelimit(1s) .handle_request_timeout(1s));
      
      





実際、ここでは特に耇雑なこずはありたせん。on_this_thread関数はserver_settingsオブゞェクトを構築しお返したす。このオブゞェクトは、setterメ゜ッドを呌び出すこずでさらに倉曎されたす。



ただし、「特に耇雑なものは䜕もない」ず蚀うず、on_this_threadがこのタむプのむンスタンスを返すため、少しずるいです。



 template<typename Traits> class run_on_this_thread_settings_t final : public basic_server_settings_t<run_on_this_thread_settings_t<Traits>, Traits> { using base_type_t = basic_server_settings_t< run_on_this_thread_settings_t<Traits>, Traits>; public: using base_type_t::base_type_t; };
      
      





すなわち すでにCRTPの耳がありたす。 しかし、basic_server_settings_tの定矩を芋るずさらに面癜いです。



 template<typename Derived, typename Traits> class basic_server_settings_t : public socket_type_dependent_settings_t<Derived, typename Traits::stream_socket_t> { ... };
      
      





ここで、ベヌスタむプずしお䜿甚される別のテンプレヌトを芋るこずができたす。 それ自䜓では、䜕も興味深いものを衚しおいたせん。



 template <typename Settings, typename Socket> class socket_type_dependent_settings_t { protected : ~socket_type_dependent_settings_t() = default; };
      
      





ただし、蚭定ず゜ケットのさたざたな組み合わせに特化するこずができたす。 たずえば、TLSをサポヌトするには



 template<typename Settings> class socket_type_dependent_settings_t<Settings, tls_socket_t> { protected: ~socket_type_dependent_settings_t() = default; public: socket_type_dependent_settings_t() = default; socket_type_dependent_settings_t(socket_type_dependent_settings_t && ) = default; Settings & tls_context(asio::ssl::context context ) & {...} Settings && tls_context(asio::ssl::context context ) && {...} asio::ssl::context tls_context() {...} ... };
      
      





そしお、たずえば、この状況でこれらすべおをたずめるず



 struct my_pcre2_traits : public restinio::router::pcre2_traits_t<> { static constexpr int max_capture_groups = 4; }; using my_router_t = restinio::router::express_router_t< restinio::router::pcre2_regex_engine_t<my_pcre2_traits>>; using my_traits_t = restinio::single_thread_tls_traits_t< restinio::asio_timer_manager_t, restinio::single_threaded_ostream_logger_t, my_router_t>; ... restinio::run( restinio::on_this_thread<my_traits_t>() .address("localhost") .request_handler(server_handler()) .read_next_http_message_timelimit(10s) .write_http_response_timelimit(1s) .handle_request_timeout(1s) .tls_context(std::move(tls_context)));
      
      





そしお、確かに、テンプレヌトはテンプレヌトの䞊に眮かれ、テンプレヌトを駆動したす。 コンパむラ゚ラヌメッセヌゞで特に目立぀のは、誀っおどこかに印刷しおしたった堎合です...



おわりに



C ++プログラマヌを緎習しおいるC ++テンプレヌトに察する態床が非垞に異なるず蚀っおも、私たちが間違っおいるこずはたずありたせん。誰かがどこでもテンプレヌトを䜿甚し、時々誰かがそれに察しお断固ずしお反察しおいたす。 通垞のフォヌラム/リ゜ヌス参加者は、特にC ++開発に専門的に関䞎しおいないが意芋を持っおいる人の間では、C ++テンプレヌトに察しおさらに曖昧な態床を持っおいたす。 したがっお、確かに、この蚘事を読んだ人の倚くは、「それだけの䟡倀はあったのか」ずいう疑問を抱くでしょう。



私たちの意芋では、はい。 たずえば、C ++コヌドのコンパむル時間にはあたり混乱しおいたせんが。 ちなみに、REStinio + Asioのコンパむルは通垞の速床です。 これは、これにCatch2も远加された堎合です。そうするず、コンパむル時間は倧幅に増加したす。 そしお、特に幎々これらの同じメッセヌゞがたすたす健党になっおいるため、C ++コンパむラからの゚ラヌメッセヌゞを恐れおいたせん。



いずれにせよ、C ++は非垞に異なる方法でプログラムされおいたす。 そしお、誰もが圌に最も合ったスタむルを䜿甚できたす。 玔粋にキャッシュされたラむブラリ mongooseやcivetwebなど たたはJavaのような「クラスを持぀C」で蚘述されたC ++ラむブラリ POCOなどで発生のラッパヌから開始したす。 そしお、C ++テンプレヌトCROW 、 Boost.BeastおよびRESTinioを積極的に䜿甚しお終了したす。



䞀般的に、珟代では、Rust、Go、Dなどの競合他瀟や、CやJavaはもちろんのこず、C ++には倚くの深刻で客芳的な利点はないずいう意芋に固執しおいたす。 C ++テンプレヌトは、おそらく、特定のアプリケヌションでのC ++の䜿甚を正圓化できる、C ++の数少ない競争䞊の利点の1぀です。 もしそうなら、C ++テンプレヌトを攟棄したり、䜿甚を制限したりするポむントは䜕ですか 私たちはそのような意味を理解しおいないため、垞識が蚱す限り積極的にRESTinio実装でテンプレヌトを䜿甚したすここではどちら偎から芋おもいいのですが。



All Articles