如何构造C++使用关键字'this'用于非静态和静态的宏?
How to construct C++ macro that uses 'this' keyword for use in non-statics AND statics?
我有一个日志宏,我想扩展它以包含调用它的对象的实例的名称。
我已经为所有要继承的对象引入了基类,例如:
class ObjectInstance
{
public:
ObjectInstance( string name );
virtual string GetName() const = 0;
}
宏看起来像这样:
#define LOG( type, msg ) LogHandler( type, msg, dynamic_cast<ObjectInstance*>( this ) )
使用LogHandler函数:
void LogHandler( string type,
string msg,
ObjectInstance* instance )
{
string instanceName = "Unknown";
if( instance != NULL )
{
instanceName = instance->GetName();
}
const string output = type + " | " + msg + " | " + instanceName;
// Do logging stuff...
}
这似乎是计划出来,但我很快意识到它不会编译时,宏从静态上下文中调用…我不知道该怎么做,到目前为止我还没有在网上找到太多信息。
非静态上下文示例:
class SomeObject : public ObjectInstance
{
SomeObject( const string& name )
:
m_name( name )
{
LOG( Info, "Created SomeObject" )
}
virtual string GetName() const { return m_name; }
}
SomeObject* ob = new SomeObject( "SomeObject123" );
期望输出:Info | Created SomeObject | SomeObject123
静态上下文示例-这当然不会编译:
class SomeStaticObject
{
static void DoSomething()
{
LOG( Info, "Doing something..." )
}
}
SomeStaticObject::DoSomething();
期望输出:Info | Doing something…|
我真的希望在静态和非静态上下文中都坚持使用一个宏,因为它已经在大型代码库中广泛使用。
我已经为所有继承
的对象引入了基类
哇!到此为止。这是c++,不是脚本语言。
为项目中的每个类添加公共基类限制了灵活性,将所有内容与日志记录器紧密耦合,并将您推向ObjectInstance
集合的滑坡,这会破坏所有类型安全。
有一个更好的方法:
首先,定义一个标签类:template<class T>
struct name_tag
{};
让LogHandler成为一个模板函数:
template<class T>
void LogHandler( string type,
string msg,
T* instance )
{
// get the name by deferring to instance_name(name_tag<>);
.... << instance_name(name_tag<std::decay_t<T>>()) << ...
}
现在我们只需要为传递给LogHandler的任何类型编写一个instance_name。
// this is your object
struct MyThing {};
// this is its name_generator.
const char* instance_name(name_tag<MyThing>)
{
return "MyThing";
}
请注意,每个名称生成器的返回类型可以是您想要的任何类型,只要它是可流的。
完整示例,包括可选内容-printer:
#include <string>
#include <iostream>
#include <iomanip>
#include <sstream>
#define LOG(type, msg, obj) LogHandler(type, msg, std::addressof(obj))
template<class T>
struct name_tag
{};
template<class T> const char* instance_name(name_tag<T>) { return typeid(T).name(); }
template<class T> const char* object_contents(const T*) { return "{}"; }
template<class T>
void LogHandler( std::string type,
std::string msg,
T* instance )
{
std::clog << "type: " << type
<< ", message: " << std::quoted(msg)
<< " : object type: " << instance_name(name_tag<std::decay_t<T>>())
<< " " << object_contents(instance)
<< std::endl;
}
// this is your object
struct MyThing {
int a = 4;
double b = 6.6;
};
// this is its name_generator.
const char* instance_name(name_tag<MyThing>)
{
return "MyThing";
}
// this is a contents printer.
std::string object_contents(const MyThing* p)
{
std::ostringstream ss;
ss << "{ a: " << p->a
<< ", b: " << p->b
<< " }";
return ss.str();
}
int main()
{
MyThing t;
LOG("whatever goes here", "hello", t);
}
预期输出:type: whatever goes here, message: "hello" : object type: MyThing { a: 4, b: 6.6 }
相关文章:
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- enable_if转换构造函数(静态强制转换,is_base_of)
- 在作为静态成员包含在另一个类中的类的构造函数中使用 cout
- C++ 模板类型的静态 lambda 成员的构造
- C++构造函数和静态成员
- 初始值设定项列表构造和静态断言
- 静态 std::map instatiation 在类的方法中调用构造函数吗?
- 错误: 无效使用非静态数据成员"应用程序::应用程序构造函数"
- 未调用的初始化静态thread_local结构的构造函数和析构函数
- 为什么具有静态存储持续时间的同一内联变量在包含在 VS2017 编译的两个翻译单元中时会构造和销毁两次
- 了解类构造函数的静态强制转换
- 为什么即使存在此静态成员,也不会构造它?
- 函数指针静态,构造函数
- 推迟C++中的静态变量构造
- boost::p ython 纯虚拟基类,具有静态工厂构造函数和 std::unique_ptr
- 在最终类中调用静态方法的静态基构造函数的设计模式
- 控制静态对象构造函数的顺序
- 来自静态变量构造函数/析构函数的异常
- c++静态工厂构造函数
- C++中,静态对象构造函数中的异常会绕过先前静态对象的析构函数