构造函数参数通过接口转发

时间:2013-04-20 16:19:08

标签: c++ reflection c++11 metaprogramming

我需要一种通用的方法来创建任何类型的实例。此任务需要从非模板化对象执行,因此我当前正在使用如下界面:

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的模板化对象来实现,该对象包含要构造的类型。 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对象不是模板化类型,因此很难提出参数转发解决方案。我不能简单地对New类中的Derived方法进行模板化,因为您无法模拟虚拟方法。

如果没有一些疯狂的代码预处理,我甚至可以问这个问题吗?

1 个答案:

答案 0 :(得分:0)

我最终在一些朋友的帮助下聚集了一个解决方案!

所以最大的问题是在反射中注册的所有类型都需要默认构造函数。为了解决这个问题,您可以使用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 );
};