我需要一种通用的方式来创建任何类型的实例。此任务需要从非模板化对象执行,因此我目前正在使用如下接口:
class Interface
{
public:
virtual void PlacementCopy( void *data, const void *src ) const = 0;
virtual void PlacementNew( void *data ) const = 0;
virtual void PlacementDelete( void *data ) const = 0;
virtual void Delete( void *data) const = 0;
virtual void Copy( void *dest, const void *src ) const = 0;
virtual void NewCopy( void **dest, const void *src ) const = 0;
virtual void *New( ) const = 0;
};
这都是自定义反射系统的一部分,因此它是这样使用的:
int *p = META( int )->Interface->New( );
*p = 10;
这通过创建一个派生自 Interface
的模板化对象来工作,该对象包含要构造的类型。接口中的New
运算符执行以下类型的默认构造:
template <typename T>
class Derived : public Interface
{
virtual void *New( void ) const override
{
return new T( );
}
};
问题:要以这种方式构造的所有类型都必须提供默认构造函数。我想以某种方式允许将任意参数传递给相关类型的构造函数。
我以某种方式需要能够做到:
MetaInfo *meta = META( SomeType );
SomeType *object = meta->New( arg1, arg2 );
在实现中可能看起来像这样:
template <typename T>
Derived : public Interface
{
template <typename ... Args>
virtual void *New( Args&& ... args ) const override
{
new T( std::forward<Args>( args ) ... );
}
};
MetaInfo
对象不是模板化类型,这使得很难提出参数转发解决方案。我不能简单地模板化Derived
类中的New
方法,因为你不能模板化虚拟方法。
如果没有一些疯狂的代码预处理,我所问的甚至可能吗?
我最终在一些朋友的帮助下收集了一个解决方案!
因此,最大的问题是要在反射中注册的所有类型都需要默认构造函数。要解决此问题,您可以使用 SNIFAE 检查是否存在默认构造函数。
struct HasDefaultCtor
{
template <typename U>
static int32 SFINAE( decltype( U( ) ) * );
template <typename U>
static int8 SFINAE( ... );
static const bool value = sizeof( SFINAE<T>( NULL ) ) == sizeof( int32 );
};
除此之外,所有非默认构造函数都必须在反射系统中手动注册,或使用预构建步骤工具生成。其他 SNIFAE 检查可用于类型检查,并确保注册的构造函数实际上与类中的实际构造函数匹配。对于实际调用New
运算符,需要进行一些运行时解析,以便确定需要哪个构造函数才能与New
调用匹配。
我希望这是有道理的,并最终对未来的某人有用。
我还对复制构造函数进行了 SNIFAE 检查:
template <typename T>
struct HasCopyCtor
{
static T MakeT( void );
template <typename U>
static int32 SFINAE( decltype( U( MakeT( ) ) ) * );
template <typename U>
static int8 SFINAE( ... );
static const bool value = sizeof( SFINAE<T>( NULL ) ) == sizeof( int32 );
};