有一个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;
}
如何重写宏以使其执行相同的功能?
预先感谢您的回答!
作为替代,
__VA_ARGS__您可以使用一组模板参数。然而,问题逐渐发展到更换
__FILE__和__LINE__。细微差别是,当使用宏时,这些预处理器指令被插入到该宏展开的位置,如果您只是将它们移动到模板函数内,它们将显示该函数的位置,而不是它的位置被称为。¿做什么(1)?出于类似的目的,标准库中有一个特殊的类
std::source_location。但是,在函数中使用它根本行不通,因为问题是相同的 - 内容将对应于该函数的位置,而不是调用它的位置。¿该怎么办(2)?在 C++ 中调用函数时,只有一种方法可以完成某些任务 - 通过向函数添加具有默认值的参数。但是,一堆模板参数不能与指定某些默认参数同时使用。
¿该怎么办(3)?在这里,您可以使用将参数包装在包装类中,在将指定默认参数的(隐式)构造函数中。但是,该类应该是通用的并且能够包装任何参数,但该包装类不能是模板,因为要将其隐式实例化为参数,编译器首先需要推断其类型,而这只能在之后执行实例化。那些。传递它的唯一方法是显式实例化它,这使得这种方法本质上等同于显式传递实例
source_location。¿该怎么办(4)?您可以使用类型擦除习惯用法并仅对包装参数的 print 方法进行模板化,而不是对整个包装器类进行模板化。
在线编译器
作为一种选择,拒绝
printf相似性。此外,您将在内部使用输出运算符。这种表示法也很有用,因为<<与函数参数的求值顺序相比,链中操作数的求值顺序得到了保证。在线编译器
最好的办法是将其包裹在
std::print/周围std::format。所以:我们将其包装
std::format_string在我们的类中以添加有关调用地点的信息。放弃这个想法
问题甚至不在于,而在于输出和 的
__VA_ARGS__地方。当使用宏时,它们被插入到调用它的地方,这意味着它们指向使用它的文件和行,但如果将其更改为函数,它们将始终指向函数本身。__FILE____LINE__C_LOG至于向函数传递可变数量的参数,是这样完成的:
另一种选择是使用
vfprintf- 这是他们的示例: