【问题标题】:How to pass an enum to a template parameter如何将枚举传递给模板参数
【发布时间】:2016-12-20 12:47:27
【问题描述】:

我有一个 xml,我从其中读取需要创建的对象的类型,问题在于如何在不使用 switch/if 语句的情况下传递枚举。

   enum ObjectType {A,B,C};

   void parseXML(const string& fileName)
   {
     //Open-read file etc...

     ObjectType objType = xmlObject.type(); <- the structure provided from the xml parser that I use(codesynthesis)

     ObjectParameters params = gatherParameters(xmlObject);

     auto createdObj = factory.createObject<objType>(params);
                                           ^^^^^
  }

需要一个常量表达式,所以我必须映射提供的类型还是有更快的方法? 如果是这样,有没有办法将枚举用作类的标记/同义词?

【问题讨论】:

  • 你投了吗?
  • 如果createObject 的模板类型需要创建对象的类型,那么您将需要一个开关来将enum 映射到一个类型。
  • @ShikatsuKagaminara 是的,它也需要一个常量表达式,因为我在括号中使用了 givenObjectType
  • 通常的方式是将枚举作为参数传递,并让函数根据开关或带有注册对象的映射返回一个对象。现在您需要由编译时多态性处理的运行时多态性。

标签: c++ c++11 templates enums


【解决方案1】:
auto magic_switch=[]( auto value, auto limit ){ // limit must be compile time type value
  return [value,limit](auto&&f){
    auto* pf=std::addressof(f);
    using ptr=decltype(pf);
    auto index=indexer<limit>();
    using R=decltype((decltype(f)(*pf))(limit));
    using Sig=R(*)(ptr pf);
    static const auto table=index(
      [](auto...Is)
      ->std::array<Sig, decltype(limit){}>
      {
        return {{
          +[](ptr pf)->R
          {
            return (decltype(f)(*pf))( decltype(Is){} );
          }...
        }};
      }
    );
    return table[value](pf);
  };
};

索引器在哪里

template<std::size_t I>using index_t=std::integral_constant<std::size_t, I>;
template<std::size_t I>constexpr index_t<I> index_k{};
template<class=void, std::size_t...Is>
auto indexer(std::index_sequence<Is...>){
  return [](auto&&f){
    return f( index_k<Is>... );
  };
}

template<std::size_t N>
auto indexer(){
  return indexer(std::make_index_sequence<N>{});
}

然后是你的代码;

auto createdObj = factory.createObject<objType>(params);
// work with it

变成:

magic_switch( objType, index_k<3> )
([&](auto index){
  auto createdObj = factory.createObject<(ObjectType)index>(params);
  // work with it
});

live example.

请注意,您最终会进入 lambda 中的子范围;没有办法避免。

【讨论】:

  • 哇,谢谢你这么快!!哈哈,我正在尝试使用您对映射的类似问题的旧答案之一的解决方案
  • 是否有任何解决方法可以在 c++11 上运行?我仅限于使用 gcc 4.8.4 和 c++11
  • @t.zak 我写了很多关于堆栈溢出的魔法开关。您必须将 lambda 主体移到一个单独的类中,并以不同的方式编写开关,但可能。谷歌应该找到很多例子(yakk,在这个网站上,“magic switch”)。发布后加版本标签的价格!
猜你喜欢
  • 2011-12-04
  • 2019-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多