0

A mirroring question of Is it possible to pass va list to variadic template

In my project for testing, there is a function:

void Func(LPCSTR format, ...) {
    va_list args;
    va_start(args, format);
    char buffer[256];
    vsprintf_s(buffer, 256, format, args);
    printf("%s\n", buffer);
    va_end(args);
}

And I write a template function:

template<typename... Args>
void FuncTemp(LPCSTR format, Args... args) {
    Func(format, args...);    //#1
}

Is the call for Func in line #1 right? I have tested my program, and it seemed to produce the correct results. Are there problems or pitfalls writing like this way?


The logic behind this: I want to realize a log writing class which can decide to write logs to local positions or submitte to servers:

Class LogWriting{
public:
...
    LogTypes mLogType;
    void WriteLogs(...){
        switch (mlogType) {
            case(LogTypes::local): {
                // need to call <void LogLocal(LPCSTR format, ...)> here
                // which CANNOT be changed.
                break;
            }
            case(LogTypes::online): {
                // need to call
                /* template<typename... Args>
                   void LogOnline(LPCSTR format, Args... args)
                   {
                       std::string strFormat = std::string(format);
                       std::string logMessage = fmt::sprintf(strFormat, args...);
                       reportLog(logMessage);
                   }
                 */
                 // which CANNOT be changed.
                break;
            }
            ...
         }
};

Because I cannot change the parameters' types of LogLocal() and LogOnline()(one is va_list and another is variadic template), I decided to set WriteLogs() as a variadic function template to suit these two functions:

template<typename... Args>
void WriteLogs(LPCSTR format, Args... args)
DerekLu
  • 79
  • 2
  • 7
  • WHY? What is the point? Note that this way you will loose type checking of format string and types of arguments. I suspect you should use `fmt` library. – Marek R Feb 25 '21 at 11:05
  • 2
    I think it's UB to pass anything that is `!std:is_trivial_v` as a `...` parameter, so you might want to `static_assert` that? Note that I am not sure about this. – lubgr Feb 25 '21 at 11:07
  • It's syntactically correct, but... there really is no virtue in such a simple wrapper. If you were doing something like parsing the format string, and verifying the type in each position is correct, then it'd be worthwhile. You'd be adding some type safety to an inherently unsafe language feature. I believe there is a talk by Andrei Alexandrescu where he pretty much does exactly that. And of course, I wouldn't do that unless I already had a legacy varargs function that is too complex to justify simply rewriting with a variadic template. – StoryTeller - Unslander Monica Feb 25 '21 at 11:16
  • @lubgr You're right, it*s UB in general, see MS compiler warning C4840 for instance. – Secundi Feb 25 '21 at 11:42
  • @MarekR Thanks for your reply. I have added the reasons I did so in the post. – DerekLu Feb 25 '21 at 12:29
  • @StoryTeller-UnslanderMonica. Thanks. And I have added the motivation I did so. In this case, what is the best way to choose? – DerekLu Feb 25 '21 at 12:32
  • You mean choose between the compromise in the other post, and making `WriteLogs` a template? I'd definitely choose a template. Path of least resistance and all. – StoryTeller - Unslander Monica Feb 25 '21 at 12:40
  • @StoryTeller-UnslanderMonica. I mean `LogLocal` and `LogOnline` have different types of parameters (va_list V.S. Args...). So I have to uniform them in the parameters of `WriteLogs()`. Hope you have understood what I mean. Sorry for my English and any confusion I have made :). – DerekLu Feb 25 '21 at 12:50

0 Answers0