提取任意类型的boost日志属性值
Extract boost log attribute values of arbitrary type
有一个日志系统,具有任意类型的属性数量。这些属性由外部程序使用 public API (函数模板)添加。这些类型是事先不知道的。打印属性值的典型方式如下(简化):
void print(logging::attribute_value const& attr)
{
auto val = logging::extract<int>(attr);
if (val) {
std::cout << "value: " << val.get() << std::endl;
}
}
在上面的例子中已经知道属性值类型是int
。如果预期的类型未知怎么办?当然,我可以这样写:
typedef boost::mpl::vector<int, std::string> types; // Expected types
logging::value_ref<types> val = logging::extract<types>(attr);
[..]
但是在那种情况下,我必须定义所有可能的类型并分别处理它们。
假设类型重载流运算符,是否有办法打印出(或转换为字符串)所有值而不考虑它们的类型?
更新
以下是更多详细信息:
// Add new attributes with arbitrary types
template<typename T>
void addProperty(const std::string &key, T && value)
{
auto attrs = boost::log::core::get()->get_thread_attributes();
attrs.erase(key);
attrs.insert(key, boost::log::attributes::make_constant(std::move(value)));
boost::log::core::get()->set_thread_attributes(attrs);
}
和另一个应该打印属性值的函数
void printProperties()
{
const auto &attrs = boost::log::core::get()->get_thread_attributes();
for (auto const &a : attrs) {
// Print all values. Types aren't known.
}
}
Of cource, I could write it like:
typedef boost::mpl::vector<int, std::string> types; // Expected types
logging::value_ref<types> val = logging::extract<types>(attr);
[..]
however in that case I have to define all possible types and handle
them separately.
是的,这将是我的第一个建议:考虑将该类型设为求和类型(绑定变体,您可以在其中访问所有绑定类型)。
Is there a way to print out (or convert to strings) all values
regardless of their types, assuming the types overload streaming
operator?
规范的替代方法是使用类型擦除。请注意,它仍然有开销,但在幕后用动态多态替换了静态多态¹。
看看在 https://www.boost.org/doc/libs/1_78_0/doc/html/boost/type_erasure/ostreamable.html
¹ 在非常特殊的情况下,哪些编译器在适当的提示下有时可以去虚拟化回静态调用,但我离题了
Is there a way to print out (or convert to strings) all values regardless of their types, assuming the types overload streaming operator?
不,Boost.Log 不支持,您必须知道属性值的名称和类型才能提取或访问它。
您可以做的是维护您自己的属性名称和格式化例程之间的映射,例如:
std::map<
logging::attribute_name,
std::function< void(std::ostream&, logging::attribute_value const&) >
> formatters;
template< typename T >
void formatter(std::ostream& strm, logging::attribute_value const& attr)
{
auto val = logging::extract< T >(attr);
if (val)
strm << val.get();
}
template<typename T>
void addProperty(const std::string &key, T && value)
{
typedef std::remove_cv_t< std::remove_reference_t< T > > value_type;
logging::attribute_name name(key);
formatters[name] = &formatter< value_type >;
boost::log::core::get()->add_thread_attribute(name,
boost::log::attributes::make_constant(std::forward< T >(value)));
}
void printProperties()
{
const auto &attrs = boost::log::core::get()->get_thread_attributes();
for (auto const &a : attrs) {
auto it = formatters.find(a.first);
if (it != formatters.end()) {
std::cout << "value: ";
it->second(std::cout, a.second.get_value());
std::cout << std::endl;
}
}
}
有一个日志系统,具有任意类型的属性数量。这些属性由外部程序使用 public API (函数模板)添加。这些类型是事先不知道的。打印属性值的典型方式如下(简化):
void print(logging::attribute_value const& attr)
{
auto val = logging::extract<int>(attr);
if (val) {
std::cout << "value: " << val.get() << std::endl;
}
}
在上面的例子中已经知道属性值类型是int
。如果预期的类型未知怎么办?当然,我可以这样写:
typedef boost::mpl::vector<int, std::string> types; // Expected types
logging::value_ref<types> val = logging::extract<types>(attr);
[..]
但是在那种情况下,我必须定义所有可能的类型并分别处理它们。
假设类型重载流运算符,是否有办法打印出(或转换为字符串)所有值而不考虑它们的类型?
更新
以下是更多详细信息:
// Add new attributes with arbitrary types
template<typename T>
void addProperty(const std::string &key, T && value)
{
auto attrs = boost::log::core::get()->get_thread_attributes();
attrs.erase(key);
attrs.insert(key, boost::log::attributes::make_constant(std::move(value)));
boost::log::core::get()->set_thread_attributes(attrs);
}
和另一个应该打印属性值的函数
void printProperties()
{
const auto &attrs = boost::log::core::get()->get_thread_attributes();
for (auto const &a : attrs) {
// Print all values. Types aren't known.
}
}
Of cource, I could write it like:
typedef boost::mpl::vector<int, std::string> types; // Expected types logging::value_ref<types> val = logging::extract<types>(attr); [..]
however in that case I have to define all possible types and handle them separately.
是的,这将是我的第一个建议:考虑将该类型设为求和类型(绑定变体,您可以在其中访问所有绑定类型)。
Is there a way to print out (or convert to strings) all values regardless of their types, assuming the types overload streaming operator?
规范的替代方法是使用类型擦除。请注意,它仍然有开销,但在幕后用动态多态替换了静态多态¹。
看看在 https://www.boost.org/doc/libs/1_78_0/doc/html/boost/type_erasure/ostreamable.html
¹ 在非常特殊的情况下,哪些编译器在适当的提示下有时可以去虚拟化回静态调用,但我离题了
Is there a way to print out (or convert to strings) all values regardless of their types, assuming the types overload streaming operator?
不,Boost.Log 不支持,您必须知道属性值的名称和类型才能提取或访问它。
您可以做的是维护您自己的属性名称和格式化例程之间的映射,例如:
std::map<
logging::attribute_name,
std::function< void(std::ostream&, logging::attribute_value const&) >
> formatters;
template< typename T >
void formatter(std::ostream& strm, logging::attribute_value const& attr)
{
auto val = logging::extract< T >(attr);
if (val)
strm << val.get();
}
template<typename T>
void addProperty(const std::string &key, T && value)
{
typedef std::remove_cv_t< std::remove_reference_t< T > > value_type;
logging::attribute_name name(key);
formatters[name] = &formatter< value_type >;
boost::log::core::get()->add_thread_attribute(name,
boost::log::attributes::make_constant(std::forward< T >(value)));
}
void printProperties()
{
const auto &attrs = boost::log::core::get()->get_thread_attributes();
for (auto const &a : attrs) {
auto it = formatters.find(a.first);
if (it != formatters.end()) {
std::cout << "value: ";
it->second(std::cout, a.second.get_value());
std::cout << std::endl;
}
}
}