Грешка при предаване на параметри в Boost.Log

За първи път експериментирах с Boost.Log и бързо се натъкнах на проблеми. Следният прост код не работи правилно за мен

#include <boost/log/common.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/sources/logger.hpp>

namespace logging = boost::log;
namespace src = boost::log::sources;

BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::logger)

static void init()
{
    logging::add_file_log("test.log");
}

int main(int, char* [])
{
    init();
    BOOST_LOG(my_logger::get()) << "hello, world";
    return 0;
}

Проблемът е, че регистрационният файл се записва във файл, наречен 00000.log вместо искания test.log. Проучвайки малко, изглежда проблемът е, че аргументът "test.log" не се предава на вътрешните класове на Boost.Log и когато това се случи, се използва шаблон на файл по подразбиране от "%N.log", което води до името на файла 00000.log, което виждам.

Boost.Log използва Boost.Parameter за внедряване на именувани параметри, така че се опитах да бъда изричен за параметъра, който използвам

logging::add_file_log(logging::keywords::file_name = "test.log");

Това се проваля по същия начин. Интересно е обаче, че ако предам два параметъра, кодът работи правилно, напр.

logging::add_file_log(logging::keywords::file_name = "test.log", 
    logging::keywords::auto_flush = true);

Не успях да определя къде е грешката, може да е Boost.Log, Boost.Parameter или грешка в компилатора. Това, което търся, е някакво обяснение за природата на грешката. Мога да заобиколя този конкретен проблем, както е показано по-горе, но ако има нещо фундаментално нередно с предаването на параметър в Boost.Log, това е доста сериозно. Ако някой има опит с тази грешка или ако може да изпробва горния код на своята платформа, ще съм благодарен.

Използвам Boost 1.74.0 и Visual Studio 2019 и C++17. Използвам статични библиотеки Boost, които са свързани статично с C++ runtime.


person john    schedule 03.09.2020    source източник


Отговори (1)


Абсолютно си прав. Това е бъг.

Намаляване докрай:

std::cerr << (kw::file_name  = "first.log")[kw::file_name | boost::filesystem::path()] << std::endl;

щампи . Малко по-информативно тестово легло:

На живо в Coliru

#include <boost/log/utility/setup/file.hpp>
#include <iostream>

int main() {
    namespace kw = boost::log::keywords;
    auto test = [](auto params) {
        std::cerr << "Non-defaulted: " << params[kw::file_name] << std::endl;
        std::cerr << "Defaulted:     " << params[kw::file_name | boost::filesystem::path()] << std::endl;
    };

    test((kw::file_name = "aaa"));
    test((kw::file_name = "bbb", kw::auto_flush = false));
    test((kw::auto_flush = false, kw::file_name = "ccc"));
}

щампи

Non-defaulted: aaa
Defaulted:     ""
Non-defaulted: bbb
Defaulted:     bbb
Non-defaulted: ccc
Defaulted:     ccc

Ясно е, че синтаксисът | filesystem::path() хвърля гаечен ключ. И се проявява само в случая с един аргумент.


Причина/поправка?

Правилният поток влиза в `arglist::operator[]:

    template <typename Default>
    inline BOOST_CONSTEXPR reference
        operator[](
            ::boost::parameter::aux::default_r_<key_type,Default> const& d
        ) const
    {
        return this->get_default(d, _holds_maybe());
    }

В

        // Helpers that handle the case when TaggedArg is empty<T>.
        template <typename D>
        inline BOOST_CONSTEXPR reference
#if defined(BOOST_PARAMETER_CAN_USE_MP11)
            get_default(D const&, ::boost::mp11::mp_false) const
#else
            get_default(D const&, ::boost::mpl::false_) const
#endif
        {
            return this->arg.get_value();
        }

В `tagged_arg::

    inline BOOST_CONSTEXPR reference get_value() const
    {
        return this->value;
    }

Неправилно работещият корпус влиза

    template <typename KW, typename Default>
    inline BOOST_CONSTEXPR Default&&
        operator[](
            ::boost::parameter::aux::default_r_<KW,Default> const& x
        ) const
    {
        return ::std::forward<Default>(x.value);
    }

Това едновременно е неправилно като KW == boost::log::v2_mt_posix::keywords::tag::file_name, така че човек би очаквал това претоварване да е взето:

    template <typename Default>
    inline BOOST_CONSTEXPR reference
        operator[](
            ::boost::parameter::aux::default_r_<key_type,Default> const&
        ) const
    {
        return this->get_value();
    }

Но. Това е дефинирано само за tagged_argument_rref, изглежда, че това е пропуск (претоварванията за default_<> са и двете, за сравнение).

Проверка на хипотезата

Ако проблемът е специфичен за default_r_<>, тогава той трябва да бъде изчезнал със стойност по подразбиране, която е lvalue:

auto args = (kw::file_name = "aaa");
path lvalue;
std::cerr << "default_r_<>: " << args[kw::file_name | path()] << "\n";
std::cerr << "default_<>: "   << args[kw::file_name | lvalue] << "\n";

Което наистина отпечатва

default_r_<>: ""
default_<>: aaa

Поправете

Логично е, че претоварването за default_r_<keyword_type, ...> трябва да се добави за tagged_argument. Наистина това работи (на моята машина).

Щях да създам PR, така че отворих проблем #104. Но когато се разклонява, се оказва, че вече има поправка в разработката:

tree fff523c8fe0a3de1c1378a2292840f217cc4d6d3
parent 0f548424a5f966fadfa7a21a759c835729cbc009
author Andrey Semashev <[email protected]> Sun Mar 15 18:13:07 2020 +0300
committer Andrey Semashev <[email protected]> Sun Mar 15 18:20:34 2020 +0300

Fix argument value selection with an rvalue default.

In C++11 mode, when named parameter pack was a single tagged argument,
parameter value was not extracted when an rvalue default value was
provided by the user (instead, the default value was returned). This
commit adds a missing overload for default_r_, which returns the parameter
value.

Fixes https://github.com/boostorg/parameter/issues/97.

Така че, да, изглежда, че корекцията е от месеци и проблемът дублира #97.

person sehe    schedule 03.09.2020
comment
Ще разгледам това малко повече - готвенето има предимство - person sehe; 03.09.2020
comment
@john намери и поправи причината само за да установи, че този проблем чака обединяване в develop. Гррр. Надяваме се, че информацията все още ви помага - person sehe; 03.09.2020
comment
Остави още коментари там. Изглежда, че поддръжката е бъркотия там: очевидно е имало корекция в разработката, която е била обединена, но очевидно всичко е било върнато, докато те са знаели, че корекция #97 е в нея. Смаян съм какво се случва там, затова оставих бележки за разработчиците да разберат това. - person sehe; 03.09.2020
comment
За вдъхновение, вашият конкретен пример работи правилно, когато поставите develop клон на Boost Parameter във вашия път за включване. Все пак е само заглавка: imgur.com/a/rKnPO9f - person sehe; 04.09.2020
comment
Благодаря за работата ви по въпроса. Добре е да знаете, че се поправя. - person john; 04.09.2020