我知道使用宏“通常”不被认为是良好的编程习惯,但我想知道如何为运营商定义宏。例如,几个boost库具有可用作(http://www.boost.org/doc/libs/1_55_0/libs/log/doc/html/log/detailed/sources.html)的宏:
BOOST_LOG(m_logger)<< "Message to log";
我试图查看BOOST_LOG的定义,但这也指向一个不同的宏,它也指向另一个等,直到我到达:
#define BOOST_LOG_STREAM_INTERNAL(logger, rec_var)\
for (::boost::log::record rec_var = (logger).open_record(); !!rec_var;)\
::boost::log::aux::make_record_pump((logger), rec_var).stream()
我的问题是,如果我有一个运算符&lt;&lt;在课堂上,我怎么能把它变成一个微观,所以我可以做:
MY_MACRO&lt;&lt;消息。
答案 0 :(得分:4)
是的,你可以这样做。
MY_MACRO
会评估一个类的实例化,比如Foo
。
在预处理器完成其工作后,MY_MACRO << message
变为Foo() << message;
。
Foo
然后为<<
等类型定义了一个重载的const char*
运算符,它会累积结果。此外,Foo
有一个析构函数,它实际上输出了那些累积的结果。一旦匿名临时Foo
超出范围,将在语句结束时调用此方法。
答案 1 :(得分:1)
正如您所指出的,在C ++中通常最好避免使用宏。
然而,放纵你的好奇心(我不推荐这样的事情)......
为此,宏需要(最终)扩展为(1)范围内的现有对象的名称(或可能是对其的引用)或(2)实例化对象的表达式。 / p>
在这两种情况下,对象都必须是具有合适operator<<()
的类型。
第一个例子是
#include <iostream>
#define A_MACRO std::cout
int main()
{
A_MACRO << "Hello world\n"; // will write to std::cout
}
第二部分的部分例子是
class X
{
public:
X() { /* set things up */ };
X &operator<<(const char * s)
{
// do something with s
return *this;
};
~X()
{
// clean up whatever resources (file handles, etc) the constructor set up
};
};
#define B_MACRO(SOMETHING) SOMETHING()
int main()
{
B_MACRO(X) << "Hello world\n";
}
(这是部分的,因为X
可能需要做一些我尚未实施的有用的东西。此示例要求宏参数是既具有默认参数又具有合适operator<<()
的类型。 operator<<()
可以是某个类的成员(如上所述),非成员友元函数或仅访问X
的公共成员的非成员函数
为了更好地理解,请阅读预处理器的工作原理(例如,如何处理扩展为使用其他宏的宏,以及它如何处理宏参数)。
实际上,尽量避免在C ++中这样做,你需要的场合很少见(例如,如果你正在编写像Boost一样的库,必须适用于具有不同特性和错误的一系列编译器)。宏有一堆不良特征,包括忽略范围。你通常最好直接使用对象或类型,而不是将它们的用法隐藏在一组宏中。
答案 2 :(得分:0)
在创建宏时,您不能使用字母,数字和美元符号以外的字符(标准不支持这些字符)。你正在谈论的库可能会将它收到的任何参数包装到一个带有重载&gt;&gt;的类中。操作
例如:
class wrapper {
int convertedType[];
public:
wrapper(aClassType a) {
//Convert a to an array of integers
}
static wrapper createWrapper(aClassType a) {
//Do the same thing as the constructor
}
aClassType toOriginalType(wrapper a) {
//perform conversion to wrapper
}
operator<< {
//perform operations on the converted type (int array in this example
}
}
#define MACRO(x) wrapper::toOriginalType(wrapper::createWrapper(x) << 5)
如果您创建了足够的转化方法,那么它就好像&gt;&gt;可以在宏中使用。