我最近从 Boost 1.72 升级到了 1.73。出于某种原因,boost::log 库似乎有一些回归,我无法通过查看源代码和调查先前版本 1.72 的示例程序增量来找到解决方案。包含以下标题似乎是错误的根源。
#include <boost/log/support/date_time.hpp>
在 Visual Studio 2019 (x64) 中包含上述内容会导致以下令人困惑的编译器输出。
1>------ Build started: Project: util, Configuration: Debug x64 ------
1>Logger.cpp
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\include\utility(151,1): error C2220: the following warning is treated as an error
1>C:\Users\johnc\main\extlibs\boost_1_73_0\boost\date_time\date_parsing.hpp(111): message : see reference to function template instantiation 'std::pair<const std::string,unsigned short>::pair<const char(&)[4],int,0>(_Other1,_Other2 &&) noexcept(false)' being compiled
1> with
1> [
1> _Other1=const char (&)[4],
1> _Other2=int
1> ]
1>C:\Users\johnc\main\extlibs\boost_1_73_0\boost\date_time\date_parsing.hpp(98): message : see reference to function template instantiation 'std::pair<const std::string,unsigned short>::pair<const char(&)[4],int,0>(_Other1,_Other2 &&) noexcept(false)' being compiled
1> with
1> [
1> _Other1=const char (&)[4],
1> _Other2=int
1> ]
1>C:\Users\johnc\main\extlibs\boost_1_73_0\boost\date_time\date_parsing.hpp(168): message : see reference to function template instantiation 'unsigned short boost::date_time::month_str_to_ushort<month_type>(const std::string &)' being compiled
1>C:\Users\johnc\main\extlibs\boost_1_73_0\boost\date_time\gregorian\parsers.hpp(49): message : see reference to function template instantiation 'date_type boost::date_time::parse_date<boost::gregorian::date>(const std::string &,int)' being compiled
1> with
1> [
1> date_type=boost::gregorian::date
1> ]
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.25.28610\include\utility(151,1): warning C4244: 'initializing': conversion from '_Ty' to '_Ty2', possible loss of data
1> with
1> [
1> _Ty=int
1> ]
1> and
1> [
1> _Ty2=unsigned short
1> ]
1>Done building project "util.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
看着utility(151,1)
我看到以下令人困惑的元编程代码(在我的情况下,_HAS_CONDITIONAL_EXPLICIT 默认启用)
#if _HAS_CONDITIONAL_EXPLICIT
template <class _Other1, class _Other2,
enable_if_t<conjunction_v<is_constructible<_Ty1, _Other1>, is_constructible<_Ty2, _Other2>>, int> = 0>
constexpr explicit(!is_convertible_v<_Other1, _Ty1> || !is_convertible_v<_Other2, _Ty2>)
pair(_Other1&& _Val1, _Other2&& _Val2) noexcept(
is_nothrow_constructible_v<_Ty1, _Other1>&& is_nothrow_constructible_v<_Ty2, _Other2>) // strengthened
: first(_STD forward<_Other1>(_Val1)), second(_STD forward<_Other2>(_Val2)) {}
#else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv
看起来问题似乎来自 date_parsing.hpp ,它初始化了一个静态 std::map 对。
#else //c+11 and beyond
static std::map<std::string, unsigned short> month_map =
{ { "jan", 1 }, { "january", 1 },
{ "feb", 2 }, { "february", 2 },
{ "mar", 3 }, { "march", 3 },
{ "apr", 4 }, { "april", 4 },
{ "may", 5 },
{ "jun", 6 }, { "june", 6 },
{ "jul", 7 }, { "july", 7 },
{ "aug", 8 }, { "august", 8 },
{ "sep", 9 }, { "september", 9 },
{ "oct", 10 }, { "october", 10 },
{ "nov", 11 }, { "november", 11 },
{ "dec", 12 }, { "december", 12 }
};
#endif
std::map<std::string, unsigned short>::const_iterator mitr = month_map.find( str );
if ( mitr != month_map.end() ) {
return mitr->second;
}
这就是我使用图书馆的方式。请参阅下面注释掉的时间戳代码和格式化程序分配(除了删除有问题的包含),以便获得编译源。
/*static*/
void
Logger::init(const std::map<std::string, fs::path>& rLogInfo)
{
// Construct the sink for the "event" channel.
// C++17 structured bindings.
for (const auto& [rChannelName, rLogPath] : rLogInfo) {
// empty path=>syslog entry
if (!rChannelName.empty()) {
if (!rLogPath.empty()) {
//static const auto gFormatter = expr::format("%1% [%2%] tid[%3%] %4%")
// % expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%H:%M:%S.%f")
// % logging::trivial::severity
// % expr::attr<attrs::current_thread_id::value_type>("ThreadID")
// % expr::smessage;
using text_sink = sinks::synchronous_sink<sinks::text_ostream_backend>;
auto sink = boost::make_shared<text_sink>();
sink->locked_backend()->auto_flush(true);
sink->locked_backend()->add_stream(
boost::make_shared<std::ofstream>(rLogPath));
//sink->set_formatter(gFormatter);
sink->set_filter(expr::attr<std::string>("Channel") == rChannelName);
logging::core::get()->add_sink(std::move(sink));
} else { // syslog entry - time-stamp not required
static const auto gFormatter = expr::format("[%1%] tid[%2%] %3%")
% logging::trivial::severity
% expr::attr<attrs::current_thread_id::value_type>("ThreadID")
% expr::smessage;
using sink_t = sinks::synchronous_sink<sinks::syslog_backend>;
// Create a new backend
#if defined (_WIN32)
auto backend = boost::make_shared<sinks::syslog_backend>(
keywords::use_impl = sinks::syslog::udp_socket_based,
keywords::facility = sinks::syslog::local7);
backend->set_target_address("localhost", 514);
#else
// Create a backend
auto backend = boost::make_shared<sinks::syslog_backend>(
keywords::use_impl = sinks::syslog::native,
keywords::facility = sinks::syslog::local7);
#endif
// We'll have to map our custom levels to the syslog levels
sinks::syslog::custom_severity_mapping<trivial::severity_level> mapping("Severity");
mapping[trivial::debug] = sinks::syslog::debug;
mapping[trivial::info] = sinks::syslog::info;
mapping[trivial::warning] = sinks::syslog::warning;
mapping[trivial::error] = sinks::syslog::error;
mapping[trivial::fatal] = sinks::syslog::critical;
backend->set_severity_mapper(mapping);
// Wrap it into the frontend and register in the core.
auto sink = boost::make_shared<sink_t>(backend);
sink->set_formatter(gFormatter);
sink->set_filter(expr::attr<std::string>("Channel") == rChannelName);
logging::core::get()->add_sink(std::move(sink));
}
}
}
// register common attributes - ThreadID, LineID, TimeStamp etc.
logging::add_common_attributes();
}