RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1594571
Accepted
michk4
michk4
Asked:2024-09-23 00:44:17 +0000 UTC2024-09-23 00:44:17 +0000 UTC 2024-09-23 00:44:17 +0000 UTC

如何替换 C++ 内联函数中的 __VA_ARGS__

  • 772

有一个C宏:

#define C_LOG(...)                                                                          \
    do {                                                                                    \
        fprintf(stdout, AC_CYAN "[INFO] %s (%d)\t " AC_RESET, __FILE__, __LINE__);          \
        fprintf(stdout, __VA_ARGS__);                                                       \
        fprintf(stdout, "\n");                                                              \
    } while (0)   

由于从C到C++的过渡,我想将其重写为内联函数,但我遇到了一个问题,即宏替代__VA_Args__。

inline void LOG(...) {
    std::cout << AC_CYAN << "[INFO]" << __FILE__ << "(" << __LINE__ << ")" << "\t" << AC_RESET;
    std::cout << /*__VA_ARGS__?*/ << std::endl;
} 

如何重写宏以使其执行相同的功能?

预先感谢您的回答!

c++
  • 3 3 个回答
  • 118 Views

3 个回答

  • Voted
  1. Best Answer
    user7860670
    2024-09-23T04:31:40Z2024-09-23T04:31:40Z

    作为替代,__VA_ARGS__您可以使用一组模板参数。

    然而,问题逐渐发展到更换__FILE__和__LINE__。细微差别是,当使用宏时,这些预处理器指令被插入到该宏展开的位置,如果您只是将它们移动到模板函数内,它们将显示该函数的位置,而不是它的位置被称为。

    ¿做什么(1)?出于类似的目的,标准库中有一个特殊的类std::source_location。但是,在函数中使用它根本行不通,因为问题是相同的 - 内容将对应于该函数的位置,而不是调用它的位置。

    ¿该怎么办(2)?在 C++ 中调用函数时,只有一种方法可以完成某些任务 - 通过向函数添加具有默认值的参数。但是,一堆模板参数不能与指定某些默认参数同时使用。

    ¿该怎么办(3)?在这里,您可以使用将参数包装在包装类中,在将指定默认参数的(隐式)构造函数中。但是,该类应该是通用的并且能够包装任何参数,但该包装类不能是模板,因为要将其隐式实例化为参数,编译器首先需要推断其类型,而这只能在之后执行实例化。那些。传递它的唯一方法是显式实例化它,这使得这种方法本质上等同于显式传递实例source_location。

    ¿该怎么办(4)?您可以使用类型擦除习惯用法并仅对包装参数的 print 方法进行模板化,而不是对整个包装器类进行模板化。

    #include <iostream>
    #include <memory>
    #include <source_location>
    #include <utility>
    #include <cstddef>
    
    class
    t_LocationPiggyback final
    {
        friend ::std::ostream &
        operator <<
        (
            ::std::ostream &
        ,   t_LocationPiggyback const & self
        );
    
        private: using
        t_Print = void
        (
            ::std::ostream & output
        ,   void const * const p_value
        );
    
        private: template
        <
            typename x_Value
        >
        static void
        Print
        (
            ::std::ostream & output
        ,   void const * const p_value
        )
        {
            output << *static_cast<x_Value const *>(p_value);
            return;
        }
    
        private: void const * m_p_value;
        private: t_Print & m_print;
        private: ::std::source_location m_location;
    
        public: template
        <
            typename x_Value
        >
        t_LocationPiggyback
        (
            x_Value const & value
        ,   ::std::source_location location = ::std::source_location::current()
        )
        noexcept
        :   m_p_value{static_cast<void const *>(::std::addressof(value))}
        ,   m_print{Print<x_Value>}
        ,   m_location{::std::move(location)}
        {
            return;
        }
    
        public: auto const &
        Get_Location
        (void)
        const noexcept
        {
            return m_location;
        }
    };
    
    inline ::std::ostream &
    operator <<
    (
        ::std::ostream & output
    ,   t_LocationPiggyback const & self
    )
    {
        self.m_print(output, self.m_p_value);
        return output;
    }
    
    template
    <
        typename... x_RestPack
    >
    void
    Log
    (
        t_LocationPiggyback first
    ,   x_RestPack &&... rest_pack
    )
    {
        auto const & location{first.Get_Location()};
        (
            (
                ::std::cout << "[INFO]" << location.file_name()
                << "(" << location.line() << ")" << "\t"
                << first
            )
            <<
            ...
            << rest_pack
        )
        << ::std::endl;
        return;
    }
    
    int
    main()
    {
        // тут произойдет следующее:
        // Log(t_LocationPiggyback{123, ::std::source_location::current()}, ", test"};
        Log(123, ", test");
        Log("test, ", 456);
        return 0;
    }
    

    在线编译器

    [INFO]/app/example.cpp(108) 123,测试
    [INFO]/app/example.cpp(109) 测试,456

    作为一种选择,拒绝printf相似性。此外,您将在内部使用输出运算符。这种表示法也很有用,因为<<与函数参数的求值顺序相比,链中操作数的求值顺序得到了保证。

    #include <iostream>
    #include <source_location>
    
    [[nodiscard]] inline auto &
    Info
    (
        ::std::source_location location = ::std::source_location::current()
    )
    {
        return ::std::cout << "[INFO]" << location.file_name()
        << "(" << location.line() << ")" << "\t";
    }
    
    int
    main()
    {
        Info() << 123 << ", test" << ::std::endl;
        Info() << "test, " << 456 << ::std::endl;
        return 0;
    }
    

    在线编译器

    • 4
  2. HolyBlackCat
    2024-09-23T12:25:25Z2024-09-23T12:25:25Z

    最好的办法是将其包裹在std::print/周围std::format。所以:

    #include <concepts>
    #include <print>
    #include <source_location>
    #include <type_traits>
    #include <utility>
    
    template <typename ...P>
    struct FmtString
    {
        std::format_string<P...> format;
        std::source_location loc;
        template <typename T>
        requires std::constructible_from<std::format_string<P...>, T &&>
        consteval FmtString(T &&format, std::source_location loc = std::source_location::current())
            : format(std::forward<T>(format)),
            loc(loc)
        {}
    };
    
    template <typename ...P>
    void Log(std::type_identity_t<FmtString<P...>> format, P &&... params)
    {
        // Или два вызова `std::print`, должно быть пошустрее.
        std::print("file:{}, line:{}, text:{}", format.loc.file_name(), format.loc.line(), std::format(format.format, std::forward<P>(params)...));
    }
    
    int main()
    {
        Log("x = {}", 42); // file:/app/example.cpp, line:28, text:x = 42
    }
    

    我们将其包装std::format_string在我们的类中以添加有关调用地点的信息。

    • 2
  3. Qwertiy
    2024-09-23T02:54:54Z2024-09-23T02:54:54Z

    放弃这个想法

    问题甚至不在于,而在于输出和 的__VA_ARGS__地方。当使用宏时,它们被插入到调用它的地方,这意味着它们指向使用它的文件和行,但如果将其更改为函数,它们将始终指向函数本身。__FILE____LINE__C_LOG


    至于向函数传递可变数量的参数,是这样完成的:

    template<typename... T> void f(const T&... t)
    

    另一种选择是使用vfprintf- 这是他们的示例:

    void WriteFormatted(FILE *stream, const char *format, ...)
    {
      va_list args;
      va_start(args, format);
      vfprintf(stream, format, args);
      va_end(args);
    }
    
    • 0

相关问题

  • 编译器和模板处理

  • 指针。找到最小数量

  • C++,关于枚举类对象初始化的问题

  • 函数中的二维数组

  • 无法使用默认构造函数创建类对象

  • C++ 和循环依赖

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5