【问题标题】:Resolve enum template parameters at run-time在运行时解析枚举模板参数
【发布时间】:2014-05-15 11:16:14
【问题描述】:

我正在尝试提出一段逻辑,它需要多个枚举并确定一个结构类型及其相应的大小以传递给第三方组件,我正在考虑使用特征来彻底解决这个问题方式:

蛮力解决方案(使用一个枚举)如下所示:

typedef enum FOO_TYPE
{
    FOO_TYPE_0 = 0,
    FOO_TYPE_1 = 1,
    ...
} FOO_TYPE;

switch (m_foo)
{
    case (FOO_TYPE_0):
    {
        FOO_0 Foo = {};
        UINT size = sizeof(Foo);
        m_thirdParty->CallFunction(&Foo, size);
    }
    break;

    case (FOO_TYPE_1):
    ...
}

我考虑使用特征通过为每个 FOO_TYPE 定义特化来解决这个问题,但是在编译过程中遇到了这个问题,因为我是在运行时而不是在编译时选择模板的特化。但是,对我来说,如何在不产生上述 switch 语句(当您考虑多种枚举类型时增长非常快)的成本的情况下解决这个问题并不是很明显。如果有人有想法,请告诉我。

template <FOO_TYPE FooType> 
struct FooTraits;

template <>
struct FooTraits<FOO_TYPE_0>
{
    typedef FOO_0 FooStruct;
};

{
    typedef FooTraits<m_foo> FooTraitsType; <== THIS USAGE CAUSES COMPILATION ERRORS
    FooTraitsType::FooStruct Foo = {};
    UINT size = sizeof(FooTraitsType::FooStruct);
    m_thirdParty->CallFunction(&Foo, size);
}

谢谢。

【问题讨论】:

  • 不可能?你必须有一个 switch 语句,除非你知道编译时的类型
  • 您需要在类型已知的地方使用模板类。当只知道运行时 m_foo 整数时,为时已晚。您没有告诉m_foo 来自哪里,以及您要解决什么问题。我不知道你需要枚举做什么。如果您只有一个非多态类型的实例,您可以使用sizeof() 确定其大小并将其传递给第三方组件。
  • 在实践中,有多种枚举类型会影响使用哪个结构,其中一些枚举(即 m_foo)可能来自第三方组件。

标签: c++ templates


【解决方案1】:

您无法在运行时使用模板执行此操作,但您可以使用其他一些选项来本地化更改。

我的偏好是使用多态性:

class Foo {
  static Foo* createFoo(FOO_TYPE type) {
  switch(type) {
     case FOO_TYPE_0:
       return new FooType0();
     case FOO_TYPE_1:
       return new FooType1();
  }
  virtual void callFunction(ThridParty thirdParty)=0;
}

class FooType0 : public Foo {
   void callFunction(ThridParty thirdParty) {
      FOO_0 Foo = {};
      UINT size = sizeof(Foo);
      m_thirdParty->CallFunction(&Foo, size);
   } 
}

class FooType1 : public Foo {
   void callFunction(ThridParty thirdParty) {
      FOO_1 Foo = {};
      UINT size = sizeof(Foo);
      m_thirdParty->CallFunction(&Foo, size);
   } 
}

你的 switch 块会变成:

// Note this leaks ... see below for non-leaking version.
createFoo(m_foo)->callFunction(m_thirdParty);

现在每个 FooTypeX 类中都有一些丑陋的重复,因此您可以使用模板化删除它:

class Foo {
  static Foo* createFoo(FOO_TYPE type) {
  switch(type) {
     case FOO_TYPE_0:
       return new FooX<FOO_1>();
     case FOO_TYPE_1:
       return new FooX<FOO_2>();
  }
  virtual void callFunction(ThridParty thirdParty)=0;
}

class FooX<BaseStruct> : public Foo {
   void callFunction(ThridParty thirdParty) {
      BaseStruct foo = {};
      UINT size = sizeof(foo);
      m_thirdParty->CallFunction(&foo, size);
   } 
} 

// A bit of a hack to prevent leaking. In real code you may want to 
// handle ownership differently.
std::unique_ptr<Foo>(createFoo(m_foo))->callFunction(m_thirdParty);

【讨论】:

  • 不应该是 static Foo* createFoo(FOO_TYPE type) 而不是:static Foo createFoo(FOO_TYPE type)
  • 确实应该,而且已经修复。
  • 这会泄漏内存,不是吗?
  • @C.R.是的,您可以通过分配给一个临时的unique_ptr 来处理这个问题。其他解决方案可能是提供一个愚蠢的不可复制的包装器,或者返回对单例实例的 const 引用(因为FooX&lt;Y&gt; 是无状态的)。
  • 我注意到你没有为 Foo 创建一个虚拟析构函数,这意味着当 unique_ptr 销毁 Foo 时,它不会调用 FooX 的析构函数。可以因为 FooX 是无状态的吗?即使是这种情况,我还是倾向于只创建一个虚拟析构函数,以避免将来 FooX 不再是无状态时出现错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多