
That's fine, but a concept is not a namespace. A concept is a set of requirements. I have no problem with putting everything associated with a particular concept in a single namespace. What I object to is your terminology.
Ok, my bad - will fix after the review. You're right - I didn't express my intention clear enough.
Second, is there any particular reason not to use shared_ptr directly?
Yes, see this : http://torjo.com/log2/doc/html/namespaceboost_1_1logging_1_1manipulator.html...
That doesn't answer my question.
I wanted a standard way of implementing a manipulator that holds non constant data. Users will usually look at existing code and then develop their-own. Using shared_ptr<> could easily be overlooked, and people could would end up with a badly implemented manipulator. Also, non_const_context makes sure the shared_ptr doesn't point to null - syntactic sugar. To answer your question : you can use shared_ptr, but the recommended way is to use non_const_context.
Level: I can't figure out from the documentation what I would need to do to model this concept.
http://torjo.com/log2/doc/html/namespaceboost_1_1logging_1_1level.html
(also, see scenario below)
What if I want to write my own level holder? All that gives is a list of level holders and levels that you provide.
Depends on what you want - the library is very flexible when it comes to filters. The simplest level holders looks like this: // the higher the level, the more critical the message struct level_filter { level_filter(int default_level = 0) : m_level(default_level) {} bool is_enabled(int level) const { return level >= m_level; } void set_enabled(int level) { m_level = level; } private: int m_level; }; Then, you can use it in code ... typedef logger_format_write< > logger_type; BOOST_DECLARE_LOG(g_l, logger_type) BOOST_DECLARE_LOG_FILTER(g_log_filter, level_filter ) #define L_(level) BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled(level) ) // logging messages const int dbg_ = 500; const int err_ = 1000; L_(dbg_) << "debug message"; L_(err_) << "error msg";
The requirements are to return a void* pointer. This is needed when http://torjo.com/log2/doc/html/caching.html and you want to cache the filter as well.
Then, are there two cases? The version of out returning an ostream and the version that processes the results directly and returns void*?
I will address this in another email.
If I remove the usage of http://torjo.com/log2/doc/html/caching.html#caching_BOOST_LOG_BEFORE_INIT_CA... then you can return anything you like. For more details, please take a look at cache_before_init_macros.hpp, line 50
Tag: The only requirement on a tag is that it must be CopyConstructable (Is it Assignable, too?). tag::holder is a effectively a fusion::set of tags.
Not really - theres'a bit of logic in that class.
Ok. That was the best guess I could come up with from namespaceboost_1_1logging_1_1tag.html. (structboost_1_1logging_1_1tag_1_1holder.html is completely useless)
It's not clear from either the tag or holder documentation how to extract tags in a formatter.
Not sure what you mean.
Suppose I write my own tag.
struct my_tag { const char* data; };
Now, I also need a formatter capable of processing it, right?
Yes.
a) what should the argument type to the formatter be? b) How do I get the value of my_tag?
I've attached an example of creating your custom formatter. I will put it on svn after the review.
If manipulators are effectively function objects, I would like to be able to just plug in existing function objects like those created by bind. If there isn't anything more to specialize then you should re-use existing concepts.
There's more to manipulators than just being a functor: - they need to have some inner typedefs, and they provide the possibility to be configured.
better to make manipulators Equality Comparable Unary Function Objects. In the case of destinations the return type is ignored, for for formatters, the result type should be the same as the argument type. For both the argument type is determined from the
"for formatters the result should be the same as the argument type" - why?
Because the result may have to be passed on to other formatters, of the same static type right? Or am I completely misunderstanding how formatters work?
They don't work like that. A formatter gets a string as argument to its operator(), and it manipulates that string. So each manipulator works isolated from the other formatters.
logger. You can use type erasure to allow them to be treated polymorphically at runtime.
Isn't this what I'm doing?
Maybe so, but I don't understand the need to use inheritance at all.
When talking about inheritance - can you tell me which part you're referring to, so I can explain? Best, John
In Christ, Steven Watanabe
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- http://John.Torjo.com -- C++ expert http://blog.torjo.com ... call me only if you want things done right /** Boost Logging library Author: John Torjo, www.torjo.com Copyright (C) 2007 John Torjo (see www.torjo.com for email) Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) See http://www.boost.org for updates, documentation, and revision history. See http://www.torjo.com/log2/ for more details */ #include <boost/logging/format_fwd.hpp> struct my_tag { my_tag(const char * data = "" /* default value */) : data(data) {} const char* data; }; namespace bl = boost::logging; typedef bl::tag::holder< bl::default_, my_tag> tag_holder; BOOST_LOG_FORMAT_MSG( tag_holder ) #include <boost/logging/format.hpp> #include <boost/logging/format/formatter/tags.hpp> typedef bl::logger_format_write< > logger_type; typedef bl::filter::no_ts filter_type; struct my_tag_formatter : bl::formatter::class_<my_tag_formatter, bl::formatter::implement_op_equal::no_context > { void operator()(tag_holder & val) const { typedef tag_holder::string_type string_type; // automatic conversion - tag holder provides this const my_tag & tag = val; string_type & str = val; // print the tag str = tag.data + str; } }; #define L_(data) BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() ) .set_tag( my_tag(data) ) BOOST_DEFINE_LOG_FILTER(g_log_filter, filter_type ) BOOST_DEFINE_LOG(g_l, logger_type) void custom_tag_class_example() { g_l()->writer().add_formatter( bl::formatter::time("$hh:$mm ") ); g_l()->writer().add_formatter( my_tag_formatter() ); g_l()->writer().add_formatter( bl::formatter::append_newline() ); g_l()->writer().add_destination( bl::destination::cout() ); g_l()->mark_as_initialized(); int i = 1; L_("tag_a ") << "this is so cool " << i++; L_("tag_b ") << "this is so cool again " << i++; } int main() { custom_tag_class_example(); }