【问题标题】:Can I get tuple of pairs of "var's name" and "var's value" with the help of the macros?我可以在宏的帮助下获得成对的“var's name”和“var's value”的元组吗?
【发布时间】:2021-04-12 08:15:55
【问题描述】:

所以我的问题...我有一个记录器类,它打印一个记录器消息,它在宏的帮助下创建。它打印不同的信息,例如函数名称、行号等。

我的消息有一个对元组,其中包含 var 的名称及其值。

using namespace std;

std::string ThisThreadGetIdString() {
    stringstream ss;
    ss << this_thread::get_id();
    return ss.str();
}

#define GET_NAME(x) #x

template<typename... Args>
auto GetTupleOfPairs(Args... args) {
    return std::tuple<std::pair<std::string, Args>...>({ GET_NAME(args), args }...);
}

#define WRITE_LOG_WITH_PARAMS(logger, messageString, logLevel, ...) \
    (logger).PrintLogMessage(LogMessage(messageString, logLevel, __LINE__, \
                             filesystem::path(__FILE__).filename().string(), \
                             __FUNCTION__, __TIMESTAMP__, ThisThreadGetIdString(), GetTupleOfPairs(__VA_ARGS__))) \

消息类ctor是

template<typename... Args>
LogMessage<Args...>::LogMessage(const std::string& messageString, const LogLevel logLevel,
    const unsigned lineNumber, const std::string& fileString,
    const std::string& functionString, const std::string& timeString,
    const std::string& threadId, const std::tuple<std::pair<std::string, Args>...>& args)
    : logLevel_(logLevel), lineNumber_(lineNumber), threadId_(threadId),
    fileString_(fileString), functionString_(functionString),
    timeString_(timeString), messageString_(messageString),
    paramTuple_(args)
{}

正如预期的那样,元组存储GetTupleOfPairs的参数名称

constexpr auto var1 = 1;
constexpr auto var2 = 1.4f;

// Output: [PROD] Thread id: [111876] Line number: 72 Message: It doesn't works properly args = 1, args = 1.4
WRITE_LOG_WITH_PARAMS(log, "It doesn't works properly", LogLevel::PROD, var1, var2);

// Have to: [PROD] Thread id: [111876] Line number: 72 Message: It doesn't works properly var1 = 1, var2 = 1.4

但这对我来说似乎没用。那么,我怎样才能得到预期的输出呢?也许我必须在宏的帮助下获得成对的“var's name”和“var's value”的元组,但我不知道它是否可能。

【问题讨论】:

    标签: c++ logging tuples c++17


    【解决方案1】:

    使用硬编码限制,您可能会这样做

    #define TAKE_11(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...)    N
    #define COUNT(...)   TAKE_11(__VA_ARGS__ __VA_OPT__(,) 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
    
    #define IDENTITY(N) N
    #define APPLY(macro, ...) IDENTITY(macro(__VA_ARGS__))
    
    #define F_0(F)
    #define F_1(F, a) F(a)
    #define F_2(F, a, b) F(a), F(b)
    #define F_3(F, a, b, c) F(a), F(b), F(c)
    #define F_4(F, a, b, c, d) F(a), F(b), F(c), F(d)
    #define F_5(F, a, b, c, d, e) F(a), F(b), F(c), F(d), F(e)
    #define F_6(F, a, b, c, d, e, f) F(a), F(b), F(c), F(d), F(e), F(f)
    #define F_7(F, a, b, c, d, e, f, g) F(a), F(b), F(c), F(d), F(e), F(f), F(g)
    #define F_8(F, a, b, c, d, e, f, g, h) F(a), F(b), F(c), F(d), F(e), F(f), F(g), F(h)
    
    #define DISPATCH(N) F_ ## N
    
    #define FOR_EACH(F, ...) IDENTITY(APPLY(DISPATCH, COUNT(__VA_ARGS__)))(F __VA_OPT__(,) __VA_ARGS__)
    
    #define MAKE_PAIR(x) std::make_pair(#x, x)
    
    #define WRITE_LOG_WITH_PARAMS(logger, messageString, logLevel, ...) \
        (logger).PrintLogMessage(LogMessage(messageString, logLevel, __LINE__, \
                                 filesystem::path(__FILE__).filename().string(), \
                                 __FUNCTION__, __TIMESTAMP__, ThisThreadGetIdString(), std::make_tuple(FOR_EACH(MAKE_PAIR __VA_OPT__(,) __VA_ARGS__))))
    

    Demo

    注意:__VA_OPT__ (C++20) 是处理空的...

    以前,您无法可靠地处理这种情况(编译器有扩展)。 您可以将每个 __VA_OPT__(x) 替换为 x 并且不处理空大小写。

    【讨论】:

    • 一个有趣的想法 à la Func 来自 C#。好吧,我希望我的手不会被这个解决方案打败 XD
    • 我不知道为什么,但它对我不起作用。元组始终为空。
    • @Chupakabra:添加了演示。只需将std::string 更改为const char* 即可自动扣除。
    • 谢谢!这是 VS 预处理器中的可怕错误。为了解决这个问题,我必须在 Configuration Properties &gt; C/C++ &gt; Command Line 下一个字符串中写入,以启用来自 Microsoft 的新的基于令牌的“现代”预处理器:/Zc: preprocessor
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2021-09-15
    • 1970-01-01
    • 1970-01-01
    • 2018-06-20
    • 2019-10-26
    • 2018-09-28
    相关资源
    最近更新 更多