Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
123 views
in Technique[技术] by (71.8m points)

c++ - Can I get tuple of pairs of "var's name" and "var's value" with the help of the macros?

So my problem... I have a logger class, that prints a logger messages, that creates with the help of macros. It prints different info such as function name, line number, etc.

My message have a tuple of pairs, that contain a name of the var and its value.

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__))) 

And message class ctor is

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)
{}

As expected, tuple stores parametr name of 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

But this seems to be useless for me. So, how can I get expected output? Maybe I must get tuple of pairs of "var's name" and "var's value" with the help of the macros, but I don't know if its possible.

question from:https://stackoverflow.com/questions/65598225/can-i-get-tuple-of-pairs-of-vars-name-and-vars-value-with-the-help-of-the

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

With hard coded limit, you might do

#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

Note: __VA_OPT__ (C++20) is to handle empty ...

Previously, you cannot reliably handle that case (there are extension from compiler). You can replace each __VA_OPT__(x) by x and doesn't handle empty case.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...