0
int temp=10;
string tempStr="hello";
LOG("test num:", temp, ", str:", tempStr);

#define LOG(...) Logger::getInstance().Print(__VA_ARGS__)

I already know how I make Print using template. But I wonder that can I make Print without template? Is it impossible? Beacuse I want to make Print method from virtual function.

class Logger : public ILogger
{
public:
virtual void Print(...) override
{
// what should I do in here?
}
}

    class ILogger
    {
    public:
    virtual void Print(...) =0;
    }
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
sensolama
  • 23
  • 4
  • 1
    Without any type information, how will you know whether the bit pattern 0x900abc is a pointer to a string or a number? – Botje Apr 28 '20 at 07:35
  • I am not sure my question is reasonable. – sensolama Apr 28 '20 at 07:44
  • @sensolama I wouldn’t say it’s unreasonable but the answer is, you can’t. However, there’s nothing preventing you from using a function template: Write your `ILogger` base class so that it provides a `Print` function template which is non-virtual, and then have a virtual `PrintImpl` function that you dispatch to internally. You will then however need to dispatch in such a way as to preserve the type information. – Konrad Rudolph Apr 28 '20 at 07:47
  • Sorry I didn't understand your comment. My purpose is to use strategy pattern. – sensolama Apr 28 '20 at 07:52
  • I believe the best option might be to split your problem. E.g. the base class `ILogger` provides a variadic template function to format the arguments into one buffer (e.g. a `std::string`). Then it may call a `virtual` member function for output of this buffer (which has to be overloaded in `Logger`). Concerning the variadic template function: You could use something already existing (e.g. `std::ostringstream`) so that you have lesser effort in your own code. – Scheff's Cat Apr 28 '20 at 08:00
  • Perhaps interesting, the 2nd part of [SO: Specializing macro with arguments](https://stackoverflow.com/a/61114589/7478597) (Please, ignore the misleading title.) – Scheff's Cat Apr 28 '20 at 08:04
  • Does this answer your question? [Abstract functions and variable arguments list](https://stackoverflow.com/questions/9376872/abstract-functions-and-variable-arguments-list) – 273K Apr 28 '20 at 08:22
  • Scheff// Thanks. But it still not available for me. Because my purpose is use stratege pattern. It means Print method can be modified in inherited method. – sensolama Apr 28 '20 at 08:22
  • S.M// yes. It is almost same. But the answer is only meet integer list. – sensolama Apr 28 '20 at 08:26
  • S.M// if there are other good solution, I will refer to your advice (implement template method in ILogger then use output string in virtual function.) But I am not sure it is best way. Anyway thanks a lot. – sensolama Apr 28 '20 at 08:53

1 Answers1

0

Assuming the 99% case is a reasonable number of parameters (10 or less), then having a separate LOG macro postfixed with a parameter count seems reasonable. Then any parameter that can be pushed via a a stream operator into the stringstream class will work.

Something like the following for supporting 1-4 parameters. Extending to 5 or more parameters is to just keep adding new macros.

void LogIt(const std::string& str)
{
    Logger::getInstance().Print(str.c_str());
}

#define LOG1(a) \
{ \
    std::ostringstream ss; \
    ss << a; \
    LogIt(ss.str()); \
}

#define LOG2(a, b) \
{ \
    std::ostringstream ss; \
    ss << a; \
    ss << b; \
    LogIt(ss.str()); \
}

#define LOG3(a, b, c) \
{ \
    std::ostringstream ss; \
    ss << a; \
    ss << b; \
    ss << c; \
    LogIt(ss.str()); \
}

#define LOG4(a, b, c, d) \
{ \
    std::ostringstream ss; \
    ss << a; \
    ss << b; \
    ss << c; \
    ss << d; \
    LogIt(ss.str()); \
}

int main()
{
    int temp = 10;
    std::string tempStr = "hello";
    LOG4("test num:", temp, ", str:", tempStr);
    return 0;
}
selbie
  • 100,020
  • 15
  • 103
  • 173