【问题标题】:how should I remove variadic functions? [duplicate]我应该如何删除可变参数函数? [复制]
【发布时间】:2018-11-09 11:13:36
【问题描述】:

我读到可变参数函数不是好的编码。

我有一个非常旧的框架,其中包含一些可变参数函数,我想删除保留调试功能的可变参数。

DEBUG(wchar_t* text, ...)

此调试函数使用相同的字符串 sintaxis %d,%f... 等调用类似 printf 的函数。

正确的方法应该是什么?

【问题讨论】:

  • 你可以使用 boost.format 吗?
  • same answer的不同问题
  • 我不会改变这一点。具有可变参数列表的函数非常适合打印、记录等。除非您想将其更改为 C++ 和类似流的接口。当然,这将是一个重大的代码更改。
  • 可以进行一大堆重写,这样你的所有格式字符串都被更改为debug_stream << "Whatever" << args << "here" << etc;,但这似乎不值得。 “没有好的编码”对“目前工作正常”并没有太大的说服力
  • 这正是我认为我应该做的事情

标签: c++ variadic-functions


【解决方案1】:

由于您标记了问题c++,例如,您可以基于c++ 流创建一个新的类/函数 - 甚至可以更改“旧”系统以使用您的新系统。然后随着时间的推移迁移到那个系统,也许在某个时候你可以摆脱旧的(在你的情况下是'DEBUG')。

【讨论】:

    【解决方案2】:

    令人惊讶的是,我建议保留调试功能,除非您愿意将整个接口更改为 C++ 的 IO 方式,也就是流。如果你打算使用printfprintf 语法,那么就让它保持原样吧。否则,将它一路现代化。

    例如,让我们保持你的实现在某个地方:

    void dbg(char* txt, ...)
    {
        va_list args;
        va_start(args, txt);
        vprintf(txt, args);
        va_end(arts);
    }
    

    是的,有一些选项可以摆脱可变参数,但如果您要保留 printf 系列语法,这样做的好处是 0:

    template <class... Args>
    auto dbg(const char* fmt, const Args&... args)
    {
        printf(fmt, args...);
    }
    

    然后你意识到char*C 更多C++ 然后你改为:

    template <class... Args>
    auto dbg(const std::string& fmt, const Args&... args)
    {
        printf(fmt.c_str(), args...);
    }
    

    然后您意识到printfC++ 更多C,现在的选择是摆脱printf 并完全废弃它。

    这个问题How to make a variadic macro for std::cout? 向您展示了一种方法,如果您仍然设置在一个函数上:

    template<typename ...Args>
    void log(Args && ...args)
    {
        (std::cout << ... << args);
    }
    

    另一种选择是制作这样的东西:

    log << "this is the " << i << " log";
    

    但让它在末尾添加换行符并非易事。

    最后,我认为最好的解决方案是使用日志库。

    【讨论】:

    • 问题,第一个代码中的 va_end 是否不必要?
    • 我的错误。已更正,谢谢。
    【解决方案3】:

    我同意@bolov 的建议,让调试功能保持原样。 但是,您可以使用std::initializer_liststd::variant(C++17 起)类型。 下面是一个小例子,它还没有处理格式说明符,但可以提供一些改进方法的想法。

    #include <iostream>
    #include <cstdlib>
    #include <variant>
    
    typedef std::variant<std::string, int, float, bool> DebugOutParam;
    std::ostream& operator << (std::ostream& os, const DebugOutParam& v)  
    {  
        if (std::holds_alternative<std::string>(v))
            os << std::get<std::string>(v);
        else if (std::holds_alternative<int>(v))
            os << std::get<int>(v);
        else if (std::holds_alternative<float>(v))
            os << std::get<float>(v);
        else if (std::holds_alternative<bool>(v))
            os << (std::get<bool>(v) ? "true" : "false");
        else
            os << "?Unsupported?";
        return os;  
    }
    typedef std::initializer_list<DebugOutParam> DebugOutParams;
    
    void dbg(std::string fmt, DebugOutParams l)
    {
        std::cout << fmt << ": ";
        for (DebugOutParams::const_iterator it = l.begin(); it != l.end(); it++)
        {
            DebugOutParam v = *it;
            std::cout << (it == l.begin() ? "" : ", ") << v;
        }
        std::cout << std::endl;
    }
    
    int main()
    {
       dbg("Test", {123, std::string("456"), true, static_cast<float>(456.789)});
    }
    

    输出

    Test: 123, 456, true, 456.789
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-01
      • 1970-01-01
      • 2018-07-26
      • 1970-01-01
      • 1970-01-01
      • 2018-09-25
      相关资源
      最近更新 更多