C ++でのリフレクションぞの私の自転車

「メンバヌ機胜のないロガヌ」ずいう出版物に觊発されお、 メタバむクを公開しお、リフレクションのために公開するこずにしたした。 ただし、単玔なロギングから始めお、前述の出版物を続けたしょう。

ロギングを実装するずき、それ自䜓のタスクは次のように蚭定されたした。


フロント゚ンドは次のようになりたす。

1. CConnectionコンストラクタヌで、次のログを蚘録したす。
TestLog::Log<LOG_NOTICE>() << *this << "connection created"; 

2. CConnectionの継承元
 public TLogHeader<'c', CConnection> 

3. CRTPを䜿甚するず、CConnectionには次のようなものがあるこずがわかりたす。
  using this_t = CConnection; int m_id; using m_id_t = TParamAccessor<this_t, decltype(this_t::m_id), &this_t::m_id>; std::string m_name; using m_name_t = TParamAccessor<this_t, decltype(this_t::m_name), &this_t::m_name>; char m_state; using m_state_t = TParamAccessor<this_t, decltype(this_t::m_state), &this_t::m_state>; using log_header_param_list_t = std::tuple<m_id_t, m_name_t, m_state_t>; 

4.そしお、このデヌタをログ行に倉換したす。
 c:23:test_conn 1:a:connection created 

コロンがリストされおいる堎所c-TLogHeaderテンプレヌトの最初のパラメヌタヌ、次に倀m_id、m_name、m_state

私の堎合、これはすべおrsyslogにさらに曞き蟌たれ、そこでMongoDBの適切なフィヌルドに解析されたすヘッダヌのタむプ、぀たりコロンの前の最初のパラメヌタヌによっお異なりたす。

珟圚、このアプロヌチは、負荷の高いシステムでの私の生産で行われおいるため、構造石はピヌクに達し、猫にずっおはより良い状態になりたす。 怠な堎合は、http//coliru.stacked-crooked.com/に実際の䟋がありたす 250行のコヌドの猫の䞋にありたすが、説明にはたくさんの文字がありたす。

音蚳ず英語の甚語がたくさんある堎合は申し蚳ありたせん。 この蚘事は完党なギャグですが、20幎間にわたっおロシアの甚語に遅れをずっおいたした。 したがっお、文献ぞの参照はありたせんが、ある時点で圌らはstackoverflow.comで私を助けたしたが、リンクを䞎えるこずは、私が理解しおいるように、砂のナヌザヌずしお私の匿名性を燃やすこずを意味したす。

だから。

パヌト1-ロギング


簡単なこずから始めたしょう

 TestLog::Log<LOG_NOTICE>() << *this << "connection created"; 


この堎合の「テンプレヌトTestLog ::ログ」は型ですただし、型を返す関数ずしお実装するこずもできたす。 ご芧のずおり、このタむプの䞀時オブゞェクトが䜜成されたす。 そしお、スコヌプを離れるずオブゞェクトが砎棄されるこずを知っおいるので、このタむプの堎合は ';'になるこずは明らかです。 したがっお、動䜜モデルは単玔です-デヌタをこのタむプにマヌゞし、その埌デストラクタが呌び出されたす。

これはTSinkクラスに実装されおいたす。
 template<int logLevel, bool isNull> struct TSink { ~TSink() { std::cerr << "std::err log line flushed: \"" << stream.str() << " \"" << std::endl; } std::stringstream stream; template<typename T> TSink<logLevel, isNull>& operator << (T&& val) { stream << val; return *this; } }; template<int logLevel> struct TSink<logLevel, true> { template<typename T> TSink<logLevel, true>& operator << (T&& val) { return *this; } }; 

ここでは、「1぀の定数を䜿甚しお、コンパむル段階で䞍芁なログレベルをオフにできるようにするために、郚分的な専門化が必芁です。 䟋LOG_NOTICEより䞊のすべおが、結果のバむナリに入らないようにしおください。 これはコンパむラヌからのプレれントですコヌドを逆コンパむルしお、出力に䜕があるかを確認したいずいう気持ちに燃えおいないので、私は100確信が持おたせん。こんにちは。 アむデアは簡単ですストリヌムぞの曞き蟌み挔算子はデヌタを操䜜したせん。䞀時オブゞェクトを䜜成し、それを削陀する前に行うすべおのこずを考慮するず、最新のコンパむラヌがすべおを最適化したす。

そしお、これはcerrの代わりにsyslogにマヌゞした堎合の倖芳です
 template<int logLevel, bool isNull> struct TSink { ~TSink() { syslog(logLevel, stream.str().c_str(), "junk"); } std::stringstream stream; template<typename T> TSink<logLevel, isNull>& operator << (T&& val) { stream << val; return *this; } }; template<int logLevel> struct TSink<logLevel, true> { template<typename T> TSink<logLevel, true>& operator << (T&& val) { return *this; } }; 

TSinkは、特定のログモゞュヌルたずえば、暙準出力ストリヌム、ファむル、syslogなどに関連付けられた最終的な実装であるこずに泚意しおください。 埌で説明するTLogクラス自䜓は、どのように実装されるかを知らず、既に特定のシンク実装を参照する特性を受け取りたす。

TestLog :: Logずは䜕かを芋おみたしょう。

これは
 static const int OUR_LOG_LEVEL = LOG_DEBUG; using TestLog = TLog<OUR_LOG_LEVEL, TLogTraitsStdErr>; 

そしお、実際には、TLogの実装
 template<int logUpTo, template<int> class log_traits> struct TLog : public log_traits<logUpTo> { using trats_t = log_traits<logUpTo>; template<int logLevel, bool isNull> using sink_type = typename trats_t::template sink_type<logLevel, isNull>; template<int neededLogLevel, int logLevel> struct TGetLogOfLevel { using type = typename std::conditional< neededLogLevel == logLevel, sink_type<neededLogLevel, (neededLogLevel > logUpTo)>, typename TGetLogOfLevel<neededLogLevel, logLevel + 1>::type >::type; }; template<int neededLogLevel> struct TGetLogOfLevel<neededLogLevel, LOG_DEBUG + 1> { using type = void; }; template<int neededLogLevel> using Log = typename TGetLogOfLevel<neededLogLevel, 0>::type; }; 

「テンプレヌト入力」で、2぀のパラメヌタヌを取埗したす。指定されたプログラムアセンブリの最倧ログレベルOUR_LOG_LEVELず、埌で継承するテンプレヌトタむプlog_traitsです。

コヌドからわかるように、log_traitsタむプには2぀の芁件がありたす。

すべおが非垞に単玔に内郚で機胜したす。再垰メタ関数TGetLogOfLevelneededLogLevel、logLevelを呌び出した結果であるLogタむプを定矩したす。

これらすべおに基づいお、log_traitsの最終的な実装を行いたす。

これを行うには、䞊蚘のlog_traits芁件を考慮しお、完成したTSinkを新しいTLogTraitsクラスにラップしたす。 ぀たり タむプtraits_typeを定矩したす
 template<int logLevel, bool isNull> using sink_type = TSink<logLevel, isNull>; 
たた、OpenLog関数を远加し、デストラクタログで閉じたす。

TLogTraitsStdErrコヌドは次のずおりです
 template<int logUpTo> struct TLogTraitsStdErr { void Open(const char* logName, int facility) { std::cerr << "std::err log opened with logName: " << logName << std::endl; } ~TLogTraitsStdErr() { std::cerr << "std::err log closed" << std::endl; } template<int logLevel, bool isNull> struct TSink { ~TSink() { std::cerr << "std::err log line flushed: \"" << stream.str() << " \"" << std::endl; } std::stringstream stream; template<typename T> TSink<logLevel, isNull>& operator << (T&& val) { stream << val; return *this; } }; template<int logLevel> struct TSink<logLevel, true> { template<typename T> TSink<logLevel, true>& operator << (T&& val) { return *this; } }; template<int logLevel, bool isNull> using sink_type = TSink<logLevel, isNull>; }; 

TLogTraitsSyslogずの類掚によっお
 template<int logUpTo> struct TLogTraitsSyslog { static void Open(const char* logName, int facility) { openlog(logName, LOG_PID | LOG_NDELAY, facility); setlogmask(LOG_UPTO(logUpTo)); } ~TLogTraitsSyslog() { closelog(); } template<int logLevel, bool isNull> struct TSink { ~TSink() { syslog(logLevel, stream.str().c_str(), "junk"); } std::stringstream stream; template<typename T> TSink<logLevel, isNull>& operator << (T&& val) { stream << val; return *this; } }; template<int logLevel> struct TSink<logLevel, true> { template<typename T> TSink<logLevel, true>& operator << (T&& val) { return *this; } }; template<int logLevel, bool isNull> using sink_type = TSink<logLevel, isNull>; }; 

そしお、もちろん、この猫をテストしたす

テストケヌスを曞く
 static const int OUR_LOG_LEVEL = LOG_DEBUG; using TestLog = TLog<OUR_LOG_LEVEL, TLogTraitsStdErr>; struct CConnection { CConnection() { TestLog::Log<LOG_NOTICE>() << "connection created"; } ~CConnection() { TestLog::Log<LOG_NOTICE>() << "connection destroyed"; } void DoSomething() { TestLog::Log<LOG_DEBUG>() << "connection is doing something"; } }; class CServer : public TestLog { public: CServer() { TestLog::Open("test_log", 1); }; int Run() { TestLog::Log<LOG_DEBUG>() << "Creating connection"; CConnection test_conn1; test_conn1.DoSomething(); return 0; } }; int main(int argc, char** argv) { CServer server; return server.Run(); } 

次の出力をコンパむルしお取埗したす。
 clang++ -std=c++11 -O2 -Wall -pedantic -pthread main.cpp && ./a.out std::err log opened with logName: test_log std::err log line flushed: "Creating connection " std::err log line flushed: "connection created " std::err log line flushed: "connection is doing something " std::err log line flushed: "connection destroyed " std::err log closed 

そしお、圌ず䞀緒にプレむしたすこのリ゜ヌスを䜕ず呌ぶべきかもわかりたせん Coliru

その結果、25行のTLogメタクラスず、log_traitsの特定の実装ごずに40行を取埗したした。 たた、芁件が満たされおいたす。䞍芁なロギングをオフにしたした。 ただ -はいのように。 透明 -メタコヌドを読むのは難しくありたせん。
私の芳点からはKISS。
どう こんにちは石2

パヌト2-反射


テストケヌスでCConnectionを拡匵する

初めに、面癜いパンがあったこずを思い出しおください。
TLogHeader <'c'、CConnection>は、 CRTPを䜿甚しお、CConnectionがこれを持っおいるこずを知っおいたす。
  using this_t = CConnection; int m_id; using m_id_t = TParamAccessor<this_t, decltype(this_t::m_id), &this_t::m_id>; std::string m_name; using m_name_t = TParamAccessor<this_t, decltype(this_t::m_name), &this_t::m_name>; char m_state; using m_state_t = TParamAccessor<this_t, decltype(this_t::m_state), &this_t::m_state>; using log_header_param_list_t = std::tuple<m_id_t, m_name_t, m_state_t>; 

これが高床なCConnectionです
 struct CConnection : public TLogHeader<'c', CConnection> { CConnection(int _id, const std::string& _name) : m_id(_id), m_name(_name), m_state('a') { TestLog::Log<LOG_NOTICE>() << *this << "connection created"; m_state = 'b'; } ~CConnection() { TestLog::Log<LOG_NOTICE>() << *this << "connection destroyed"; } void DoSomething() { TestLog::Log<LOG_DEBUG>() << *this << "connection is doing something"; m_state = 'c'; } using this_t = CConnection; int m_id; using m_id_t = TParamAccessor<this_t, decltype(this_t::m_id), &this_t::m_id>; std::string m_name; using m_name_t = TParamAccessor<this_t, decltype(this_t::m_name), &this_t::m_name>; char m_state; using m_state_t = TParamAccessor<this_t, decltype(this_t::m_state), &this_t::m_state>; using log_header_param_list_t = std::tuple<m_id_t, m_name_t, m_state_t>; }; 

もちろん、これはすべお、PARAMint、m_idなどの単玔なマクロでラップできたすが、正気のためにはしたせん。

TParamAccessorは、クラス倉数ぞの参照を返す1぀の静的GetRef関数が定矩されおいる型です。
このように
 struct TParamAccessorDefaultTraits { }; template <typename _object_t, typename _value_type, _value_type _object_t::*member_t, typename _traits_t = TParamAccessorDefaultTraits> struct TParamAccessor : public _traits_t { using traits_t = _traits_t; using object_t = _object_t; using value_type = _value_type; static value_type& GetRef(object_t& data) { return data.*member_t; } }; 
したがっお、これをsink_typeストリヌムにプッシュするには、CConnection :: log_header_param_list_tを介しおTLogHeader <'c'、CConnection>から継承し、sink_type << TParamAccessor :: GetRefオブゞェクトを呌び出す必芁がありたす。

譊告メタオプションfor_eachを芋るたで、ここでは理解するのが少し難しいでしょう。

TLogHeaderクラスを取埗したす
 template<char moduleName, typename object_t> struct TLogHeader { template<size_t idx, typename accessor_t> struct TLogHeaderWriter { using type = TLogHeaderWriter<idx, accessor_t>; static void call(typename accessor_t::object_t& obj, std::stringstream& out) { typename accessor_t::value_type& val = accessor_t::GetRef(obj); out << val << ":"; } }; template<typename sink_type> friend sink_type& operator << (sink_type& sink, object_t& val) { std::stringstream header; using writers = typename for_each<typename object_t::log_header_param_list_t>::template instantiate<TLogHeaderWriter>; for_each<writers>::call(*static_cast<object_t*>(&val), header); sink << moduleName << ":" << header.str(); return sink; } }; 

TLogHeaderは、ストリヌムぞのオヌバヌロヌド曞き蟌み挔算子ずいう1぀の関数のみを蚘述したす。
ここでは、2぀の装いでfor_eachを確認したす。
  1. TLogHeaderWriterのすべおのむンスタンス<from object_t :: log_header_param_list_t ::各タむプ内から>がタプルずしお返されるラむタヌのタむプを決定するメタ関数呌び出し
  2. ラむタヌで定矩されたすべおのタむプの静的呌び出し関数の呌び出し

for_eachのメタ仮説を行いたしょう

これを行うには、TLogHeaderを単玔化しおメタ関数のみを呌び出したす
 template<char moduleName, typename object_t> struct TLogHeader { template<size_t idx, typename accessor_t> struct TLogHeaderWriter { using type = TLogHeaderWriter<idx, accessor_t>; }; template<typename sink_type> friend sink_type& operator << (sink_type& sink, object_t& val) { using writers = typename for_each<typename object_t::log_header_param_list_t>::template instantiate<TLogHeaderWriter>; return sink; } }; 

そしお、メタ関数を曞きたす。
免責事項なぜなら 簡単にするために、最終コヌドをカットし、テストしたせんでした。 最埌のものは、埌でラむブでテストできたす。

念のため、私にずっお最も明確な甚語は、「メタ機胜ずは、プログラムをコンパむルする段階で実行される機胜であり、その結果は新しいタむプである」ずいうこずですすべお自分の蚀葉で

私はコヌドでコメントしたす さらに少し混乱したす。

For_eachコヌド
 //////////////////////////////////////////////////////////////// // append to tuple //-       new_t //    tuple    template argument pack,       template<typename new_t, typename... other_t> struct append_to_tuple { using type = std::tuple<other_t..., new_t>; }; template<typename new_t, typename... other_t> struct append_to_tuple<new_t, std::tuple<other_t...>> { using type = std::tuple<other_t..., new_t>; }; //////////////////////////////////////////////////////////////// // for_each_impl // for_each -  ,   func_t  instatiate, //,         tuple  append_to_tuple // ,  ,           template<size_t i, typename... args_t> struct for_each_impl { using this_type = typename std::tuple_element<i, std::tuple<args_t...>>::type; using prev_type = for_each_impl<i - 1, args_t...>; template<template<size_t, typename> class func_t> using instantiate = typename append_to_tuple< typename func_t<i, this_type>::type, typename prev_type::template instantiate<func_t> >::type; }; //       //       template<typename... args_t> struct for_each_impl<0, args_t...> { using this_type = typename std::tuple_element<0, std::tuple<args_t...>>::type; template<template<size_t, typename> class func_t> using instantiate = std::tuple<typename func_t<0, this_type>::type>; }; /////////////////////////////////////////////////////////////// // for_each // . //  for_each_impl,     // +     tuple< >  tuple<>   template<typename... args_t> struct for_each { using prev_type = for_each_impl<sizeof...(args_t) - 1, args_t...>; template<template<size_t, typename> class func_t> using instantiate = typename prev_type::template instantiate<func_t>; }; template<typename... args_t> struct for_each<std::tuple<args_t...>> : public for_each<args_t...> { }; template<> struct for_each<std::tuple<>> { template<template<size_t, typename> class func_t> using instantiate = std::tuple<>; }; 

したがっお、writers = typename for_each <typename object_t :: log_header_param_list_t> :: template instantiate;を䜿甚しお取埗したした。 䜜家が展開する堎所
 std::tuple< TLogHeaderWriter<0, TParamAccessor<CConnection, decltype(CConnection::m_id), &CConnection::m_id>>, TLogHeaderWriter<1, TParamAccessor<CConnection, decltype(CConnection::m_name), &CConnection::m_name>>, TLogHeaderWriter<2, TParamAccessor<CConnection, decltype(CConnection::m_state), &CConnection::m_state>> >; 

これらの型を通過し、GetRefを呌び出しおからストリヌムに曞き蟌むこずは残っおいたす。

for_eachの実行時の仮説を立おたしょう

そしおすぐに、拡匵されたfor_eachを芋おください。これは、静的関数呌び出しに呌び出しを远加したす泚意する䟡倀があるだけで、残りは倉曎されたせん。
そしおここにある-最埌のコヌド
 //////////////////////////////////////////////////////////////// // for_each_impl template<size_t i, typename... args_t> struct for_each_impl { using this_type = typename std::tuple_element<i, std::tuple<args_t...>>::type; using prev_type = for_each_impl<i - 1, args_t...>; template<template<size_t, typename> class func_t> using instantiate = typename append_to_tuple< typename func_t<i, this_type>::type, typename prev_type::template instantiate<func_t> >::type; template<typename object_t, typename... call_args_t> static void call(object_t&& obj, call_args_t&&... args) { prev_type::call(std::forward<object_t>(obj), std::forward<call_args_t>(args)...); this_type::call(std::forward<object_t>(obj), std::forward<call_args_t>(args)...); } }; template<typename... args_t> struct for_each_impl<0, args_t...> { using this_type = typename std::tuple_element<0, std::tuple<args_t...>>::type; template<template<size_t, typename> class func_t> using instantiate = std::tuple<typename func_t<0, this_type>::type>; template<typename object_t, typename... call_args_t> static void call(object_t&& obj, call_args_t&&... args) { this_type::call(std::forward<object_t>(obj), std::forward<call_args_t>(args)...); } template<typename object_t> static void call(object_t&& obj) { this_type::call(std::forward<object_t>(obj)); } }; /////////////////////////////////////////////////////////////// // for_each template<typename... args_t> struct for_each { using prev_type = for_each_impl<sizeof...(args_t) - 1, args_t...>; template<template<size_t, typename> class func_t> using instantiate = typename prev_type::template instantiate<func_t>; template<typename object_t, typename... call_args_t> static object_t call(object_t&& obj, call_args_t&&... args) { prev_type::call(std::forward<object_t>(obj), std::forward<call_args_t>(args)...); return obj; } template<typename object_t> static object_t call(object_t&& obj) { prev_type::call(std::forward<object_t>(obj)); return obj; } }; template<typename... args_t> struct for_each<std::tuple<args_t...>> : public for_each<args_t...> { }; template<> struct for_each<std::tuple<>> { template<template<size_t, typename> class func_t> using instantiate = std::tuple<>; template<typename object_t, typename... call_args_t> static object_t call(object_t&& obj, call_args_t&&... args) { return obj; } template<typename object_t> static object_t call(object_t&& obj) { return obj; } }; 

ここでコメントする必芁は特にないず思いたす。呌び出しは少なくずも1぀のパラメヌタヌを受け取りたす。これはプロキシオブゞェクトであり、䜜業の最埌に戻り、残りのパラメヌタヌは呌び出し呌び出しに転送されたす。
私たちの堎合、これはTLogHeaderWirter :: callです。
 static void call(typename accessor_t::object_t& obj, std::stringstream& out) { typename accessor_t::value_type& val = accessor_t::GetRef(obj); out << val << ":"; } 
where accessor_t :: object_t = CConnection
そしおもちろん、完璧な転送は重芁です

パヌト3-結論


党コヌド
 #include <cstdlib> #include <iostream> #include <sstream> #include <syslog.h> static const int OUR_LOG_LEVEL = LOG_DEBUG; // = LOG_NOTICE; // log up to LOG_DEBUG output: //std::err log opened with logName: test_log //std::err log line flushed: "s:1:test server:Creating connection " //std::err log line flushed: "c:23:test_conn 1:a:connection created " //std::err log line flushed: "c:23:test_conn 1:b:connection is doing something " //std::err log line flushed: "c:23:test_conn 1:c:connection destroyed " //std::err log closed // log up to LOG_NOTICE output: //std::err log opened with logName: test_log //std::err log line flushed: "c:23:test_conn 1:a:connection created " //std::err log line flushed: "c:23:test_conn 1:c:connection destroyed " //std::err log closed // ---------------------------- for_each.h start ----------------------------// #include <tuple> #include <utility> namespace helpers { //////////////////////////////////////////////////////////////// // param accessor struct TParamAccessorDefaultTraits { }; template <typename _object_t, typename _value_type, _value_type _object_t::*member_t, typename _traits_t = TParamAccessorDefaultTraits> struct TParamAccessor : public _traits_t { using traits_t = _traits_t; using object_t = _object_t; using value_type = _value_type; static value_type& GetRef(object_t& data) { return data.*member_t; } }; //////////////////////////////////////////////////////////////// // append to tuple template<typename new_t, typename... other_t> struct append_to_tuple { using type = std::tuple<other_t..., new_t>; }; template<typename new_t, typename... other_t> struct append_to_tuple<new_t, std::tuple<other_t...>> { using type = std::tuple<other_t..., new_t>; }; //////////////////////////////////////////////////////////////// // for_each_impl template<size_t i, typename... args_t> struct for_each_impl { using this_type = typename std::tuple_element<i, std::tuple<args_t...>>::type; using prev_type = for_each_impl<i - 1, args_t...>; template<template<size_t, typename> class func_t> using instantiate = typename append_to_tuple< typename func_t<i, this_type>::type, typename prev_type::template instantiate<func_t> >::type; template<typename object_t, typename... call_args_t> static void call(object_t&& obj, call_args_t&&... args) { prev_type::call(std::forward<object_t>(obj), std::forward<call_args_t>(args)...); this_type::call(std::forward<object_t>(obj), std::forward<call_args_t>(args)...); } }; template<typename... args_t> struct for_each_impl<0, args_t...> { using this_type = typename std::tuple_element<0, std::tuple<args_t...>>::type; template<template<size_t, typename> class func_t> using instantiate = std::tuple<typename func_t<0, this_type>::type>; template<typename object_t, typename... call_args_t> static void call(object_t&& obj, call_args_t&&... args) { this_type::call(std::forward<object_t>(obj), std::forward<call_args_t>(args)...); } template<typename object_t> static void call(object_t&& obj) { this_type::call(std::forward<object_t>(obj)); } }; /////////////////////////////////////////////////////////////// // for_each template<typename... args_t> struct for_each { using prev_type = for_each_impl<sizeof...(args_t) - 1, args_t...>; template<template<size_t, typename> class func_t> using instantiate = typename prev_type::template instantiate<func_t>; template<typename object_t, typename... call_args_t> static object_t call(object_t&& obj, call_args_t&&... args) { prev_type::call(std::forward<object_t>(obj), std::forward<call_args_t>(args)...); return obj; } template<typename object_t> static object_t call(object_t&& obj) { prev_type::call(std::forward<object_t>(obj)); return obj; } }; template<typename... args_t> struct for_each<std::tuple<args_t...>> : public for_each<args_t...> { }; template<> struct for_each<std::tuple<>> { template<template<size_t, typename> class func_t> using instantiate = std::tuple<>; template<typename object_t, typename... call_args_t> static object_t call(object_t&& obj, call_args_t&&... args) { return obj; } template<typename object_t> static object_t call(object_t&& obj) { return obj; } }; } //namespace helpers // ---------------------------- for_each.h end ----------------------------// using namespace helpers; ////////////////////////////////////////////////////////////////////////////////////////// template<int logUpTo> struct TLogTraitsStdErr { static void Open(const char* logName, int facility) { std::cerr << "std::err log opened with logName: " << logName << std::endl; } ~TLogTraitsStdErr() { std::cerr << "std::err log closed" << std::endl; } template<int logLevel, bool isNull> struct TSink { ~TSink() { std::cerr << "std::err log line flushed: \"" << stream.str() << " \"" << std::endl; } std::stringstream stream; template<typename T> TSink<logLevel, isNull>& operator << (T&& val) { stream << val; return *this; } }; template<int logLevel> struct TSink<logLevel, true> { template<typename T> TSink<logLevel, true>& operator << (T&& val) { return *this; } }; template<int logLevel, bool isNull> using sink_type = TSink<logLevel, isNull>; }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template<int logUpTo> struct TLogTraitsSyslog { static void Open(const char* logName, int facility) { openlog(logName, LOG_PID | LOG_NDELAY, facility); setlogmask(LOG_UPTO(logUpTo)); } ~TLogTraitsSyslog() { closelog(); } template<int logLevel, bool isNull> struct TSink { ~TSink() { syslog(logLevel, stream.str().c_str(), "junk"); } std::stringstream stream; template<typename T> TSink<logLevel, isNull>& operator << (T&& val) { stream << val; return *this; } }; template<int logLevel> struct TSink<logLevel, true> { template<typename T> TSink<logLevel, true>& operator << (T&& val) { return *this; } }; template<int logLevel, bool isNull> using sink_type = TSink<logLevel, isNull>; }; ////////////////////////////////////////////////////////////////////////////////////////// template<char moduleName, typename object_t> struct TLogHeader { template<size_t idx, typename accessor_t> struct TLogHeaderWriter { using type = TLogHeaderWriter<idx, accessor_t>; static void call(typename accessor_t::object_t& obj, std::stringstream& out) { typename accessor_t::value_type& val = accessor_t::GetRef(obj); out << val << ":"; } }; template<typename sink_type> friend sink_type& operator << (sink_type& sink, object_t& val) { std::stringstream header; using writers = typename for_each<typename object_t::log_header_param_list_t>::template instantiate<TLogHeaderWriter>; for_each<writers>::call(*static_cast<object_t*>(&val), header); sink << moduleName << ":" << header.str(); return sink; } }; ////////////////////////////////////////////////////////////////////////////////////////// template<int logUpTo, template<int> class log_traits = TLogTraitsSyslog> struct TLog : public log_traits<logUpTo> { using trats_t = log_traits<logUpTo>; template<int logLevel, bool isNull> using sink_type = typename trats_t::template sink_type<logLevel, isNull>; template<int neededLogLevel, int logLevel> struct TGetLogOfLevel { using type = typename std::conditional< neededLogLevel == logLevel, sink_type<neededLogLevel, (neededLogLevel > logUpTo)>, typename TGetLogOfLevel<neededLogLevel, logLevel + 1>::type >::type; }; template<int neededLogLevel> struct TGetLogOfLevel<neededLogLevel, LOG_DEBUG + 1> { using type = void; }; template<int neededLogLevel> using Log = typename TGetLogOfLevel<neededLogLevel, 0>::type; }; /////////////////////////////// //testcase using TestLog = TLog<OUR_LOG_LEVEL, TLogTraitsStdErr>; struct CConnection : public TLogHeader<'c', CConnection> { CConnection(int _id, const std::string& _name) : m_id(_id), m_name(_name), m_state('a') { TestLog::Log<LOG_NOTICE>() << *this << "connection created"; m_state = 'b'; } ~CConnection() { TestLog::Log<LOG_NOTICE>() << *this << "connection destroyed"; } void DoSomething() { TestLog::Log<LOG_DEBUG>() << *this << "connection is doing something"; m_state = 'c'; } using this_t = CConnection; int m_id; using m_id_t = TParamAccessor<this_t, decltype(this_t::m_id), &this_t::m_id>; std::string m_name; using m_name_t = TParamAccessor<this_t, decltype(this_t::m_name), &this_t::m_name>; char m_state; using m_state_t = TParamAccessor<this_t, decltype(this_t::m_state), &this_t::m_state>; using log_header_param_list_t = std::tuple<m_id_t, m_name_t, m_state_t>; }; class CServer : public TLogHeader<'s', CServer>, public TestLog { public: CServer() : m_id(1), m_name("test server") { TestLog::Open("test_log", 1); }; int Run() { TestLog::Log<LOG_DEBUG>() << *this << "Creating connection"; CConnection test_conn1(23, "test_conn 1"); test_conn1.DoSomething(); return 0; } using this_t = CServer; int m_id; using m_id_t = TParamAccessor<this_t, decltype(this_t::m_id), &this_t::m_id>; std::string m_name; using m_name_t = TParamAccessor<this_t, decltype(this_t::m_name), &this_t::m_name>; using log_header_param_list_t = std::tuple<m_id_t, m_name_t> ; }; int main(int argc, char** argv) { CServer server; return server.Run(); } 

これが既補の䟋です。
2぀のfor_eachオプションの実装をさらに100行远加したした。
そしお、䟋を芋るず、それらが別のファむルfor_each.hにあるこずがわかりたす。
なぜなら私は歎史の5぀のモゞュヌルで積極的に䜿甚しおいたす゚ンドシステムの゚ンディアンを考慮しおpostgresず通信するネむティブバむナリ圢匏、バッファからパケットを展開し、コンパむル段階でWeb゜ケットにメッセヌゞ圢匏を生成するなど

そしお私が蚀ったように石レセプション

PSコヌドの䜜成には半日かかり、Habrの日の蚘事は...パラドックスです

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


All Articles