C ++ сложенное выражение с пользовательским классом - PullRequest
2 голосов
/ 19 февраля 2020

Я хотел бы создать функцию журнала с несколькими параметрами, и я также хочу вызвать функцию журнала с моим классом.
Вот мой код (компилятор: Visual studio 2019 или x86-64 gcc9.2)

Вопрос 1> Я не могу понять функцию журнала. Можно ли использовать такое выражение складывания? (эта функция взята из библиотеки spdlog)

Вопрос 2> Как я могу использовать функцию log с классом Mystruct?
log(1, MyStruct(1, 1.1f, "hello world"s)); // compiler error

#include <cstdio>
#include <iostream>
#include <string>
#include <sstream>

template<typename ... Args>
void log(int level, Args const& ... args)
{
    std::ostringstream stream;
    using List = int[];
    (void)List {
        0, ((void)(stream << args), 0) ...
    };
    std::cout << stream.str() << std::endl;
}

class MyStruct
{
public:
    int val1 = 0;
    float val2 = 0.f;
    std::string val3;

    MyStruct(int v1, float v2, std::string_view const& v3) : val1(v1), val2(v2), val3(v3) {};
    std::string to_string() const
    {
        std::stringstream stream;
        stream << "val1=" << val1 << ", val2=" << val2 << ",val3=" << val3;
        return stream.str();
    }
};

std::ostringstream& operator<< (std::ostringstream& stream, MyStruct&& val)
{
    auto str = val.to_string();
    std::operator <<(stream, str);
    return stream;
}

void work_good()
{
    using namespace std::string_literals;  
    log(1, 1.1f, "hello world"s);
}

void compile_error()
{
    using namespace std::string_literals;  
    log(1, MyStruct(1, 1.1f, "hello world"s));
}

int main()
{
    work_good();
}

Ответы [ 2 ]

3 голосов
/ 19 февраля 2020

Вопрос 1> Я не могу понять функцию журнала. Можно ли использовать такое выражение сгиба?

Если быть точным, то оно не использует выражение сгиба (начиная с C ++ 17). См. расширение пакета , которое было поддержано в C ++ 11, и да, это допустимое использование, как в log.

Паттерн с многоточием, в котором имя по меньшей мере, один пакет параметров появляется, по меньшей мере, один раз, расширяется до нуля или более разделенных запятыми экземпляров шаблона, где имя пакета параметров заменяется каждым из элементов из пакета в порядке.

и

Вопрос 2> Как я могу использовать функцию журнала с классом Mystruct?

Вы объявили operator<<, взяв MyStruct в качестве rvalue-reference , но в log аргументы передаются в operator<< как lvalue, который не может быть привязан к rvalue-reference. Вы можете изменить operator<< на lvalue-referenct на const, что применимо как для lvalue, так и для rvalue. например,

std::ostringstream& operator<< (std::ostringstream& stream, const MyStruct& val)
{
    auto str = val.to_string();
    std::operator <<(stream, str);
    return stream;
}

LIVE

0 голосов
/ 19 февраля 2020

Я изменил код с ответом. Я хочу, чтобы функция журнала была более обобщенной c

namespace nlog
{
    class MyStruct
    {
    public:
        int val1 = 0;
        float val2 = 0.f;
        std::string val3;

        MyStruct(int v1, float v2, std::string_view const& v3) : val1(v1), val2(v2), val3(v3) {};
        std::string to_string() const
        {
            std::stringstream stream;
            stream << "val1=" << val1 << ", val2=" << val2 << ",val3=" << val3;
            return stream.str();
        }
    };

    template < typename T, typename decltype(std::declval<T>().to_string())* = nullptr>
        std::ostream& operator<< (std::ostream& stream, T&& val)
    {
        auto str = val.to_string();
        std::operator <<(stream, str);
        return stream;
    }


    template <typename ... Ts>
    void tolog(Ts && ...args)
    {
        std::stringstream strbuf;
        (strbuf << ... << std::forward<Ts>(args));

        std::cout << strbuf.str() << std::endl;
    }

    template <typename ... Ts>
    void toout(Ts && ...args)
    {
        (std::cout << ... << args);
    }
};

namespace nlog
{
    void Test1()
    {
        using namespace std::string_literals;
        std::stringstream strbuf;
        strbuf << MyStruct(0, 0.1f, "Eric"s);
        std::cout << strbuf.str() << std::endl;
    }

    void Test2()
    {
        using namespace std::string_literals;
        tolog(1, 1.1f, "hello world"s);
    }

    void Test3()
    {
        using namespace std::string_literals;
        tolog("I like this func val=", 100, ", youvalue=", 1.0f, ", MyStruct=",  MyStruct(0, 0.1f, "Eric"s));
    }
};

int main()
{
    nlog::Test1();
    nlog::Test2();
    nlog::Test3();
}
...