0

I have the following macro that works for this case:

#define logger(p) loggerImpl(p, #p)

void loggerImpl(int paramValue, const std::string paramName) {
   std::cout << paramName << ": " << paramValue << std::endl;
}

int myVarA = 33;
logger(myVarA);
// myVarA: 33

But I will like to extend it to make this work:

int myVarA = 33;
int myVarB = 22;
int myVarC = 11;

logger(myVarA, myVarB);
// myVarA: 33
// myVarB: 22

logger(myVarA, myVarB, myVarC);
// myVarA: 33
// myVarB: 22
// myVarC: 11

Could be possible to iterate through each param with a macro?

ellipticaldoor
  • 1,122
  • 11
  • 24
  • 2
    You should forget macros, C++ has much better solutions. For example [variadic templates, a.k.a parameter packs](https://en.cppreference.com/w/cpp/language/parameter_pack). – Lukas-T Nov 29 '20 at 21:09
  • 1
    Please add a link to your previous question as motivation for why you want a macro in the first place. Otherwise, as churill points out, macros are not a good idea in general. – cigien Nov 29 '20 at 21:10
  • here is the link to the previous question https://stackoverflow.com/questions/65064054/is-it-possible-in-c-to-get-as-an-string-the-name-of-a-variable-that-was-passed/65064105 – ellipticaldoor Nov 29 '20 at 21:21
  • @churill That is not possible in this case because the example uses the stringification (or stringizer) operator which requires a macro. – François Andrieux Nov 29 '20 at 21:22
  • Add the link into the question please, and explain briefly why you want to use that solution. "It solves my problem" is a good enough reason :) – cigien Nov 29 '20 at 21:22
  • You should use either `std::string_view` or `const char*` for `paramName` instead of `std::string` because it appears to only be used with string literals. Using `std::string` will require a string copy to be created every time something is logged. Possibly requiring dynamic allocation. – François Andrieux Nov 29 '20 at 21:23
  • @FrançoisAndrieux True, but OP mentioned in the previous post that this is only for debugging purposes, and won't end up in production code, so the performance argument is not too relevant. – cigien Nov 29 '20 at 21:26
  • @FrançoisAndrieux True, but you could just use a mcro to build a struct of name and value. This would also allow the flexibility of printing rvalues. – Lukas-T Nov 30 '20 at 06:09

1 Answers1

0

I went for this solution in the end

#pragma once

// clang-format off
#define _logger_macro(_1, _2, _3, _4, _5, NAME, ...) NAME
#define logger_1(_1) loggerImpl(_1, #_1)
#define logger_2(_1, _2) loggerImpl(_1, #_1); logger_1(_2)
#define logger_3(_1, _2, _3) loggerImpl(_1, #_1); logger_2(_2, _3)
#define logger_4(_1, _2, _3, _4) loggerImpl(_1, #_1); logger_3(_2, _3, _4)
#define logger_5(_1, _2, _3, _4, _5) loggerImpl(_1, #_1); logger_4(_2, _3, _4, _5)
#define logger(...) \
  _logger_macro(__VA_ARGS__, logger_5, logger_4, logger_3, logger_2, logger_1)(__VA_ARGS__);
// clang-format on

void logString(const std::string paramValue, const std::string paramName) {
  std::string toLog =
    paramValue == paramName ? paramValue : paramName + ": " + paramValue;
  std::cout << toLog << std::endl;
}

void loggerImpl(const int paramValue, const char *paramName) {
  logString(std::to_string(paramValue), paramName);
}

void loggerImpl(const float paramValue, const char *paramName) {
  logString(std::to_string(paramValue), paramName);
}

void loggerImpl(const double paramValue, const char *paramName) {
  logString(std::to_string(paramValue), paramName);
}

const std::string IS_TRUE = "true";
const std::string IS_FALSE = "false";
void loggerImpl(const bool paramValue, const char *paramName) {
  logString(paramValue ? IS_TRUE : IS_FALSE, paramName);
}

void loggerImpl(const char *paramValue, const char *paramName) {
  auto paramNameString = std::string(paramName);
  logString(paramValue, paramNameString.substr(1, paramNameString.size() - 2));
}

void loggerImpl(const std::string paramValue, const char *paramName) {
  logString(paramValue, paramName);
}
ellipticaldoor
  • 1,122
  • 11
  • 24