【问题标题】:How to automate creation of tuples of template classes based on elements of an array?如何根据数组元素自动创建模板类的元组?
【发布时间】:2015-11-28 09:40:46
【问题描述】:

我有一个std::array,其中填充了所有类型的枚举。我想实现基于我的元组 关于这个。

class CompBase
{
public:
    enum CompType{
        INPUT,
        GRAPHICS
        // ( + 5-10 additional types)
    };

    static const std::array<CompType, 2> compTypeArr;
};

const std::array<CompBase::CompType, 2> CompBase::compTypeArr =
{
    CompBase::INPUT,
    CompBase::GRAPHICS
};

template<CompBase::CompType compType_e>
class CompHolder {}; // owns one component

template<CompBase::CompType compType_e>
class CompContainer {}; // references N components

class CompInterface
{
    // ...
private:
    std::tuple // I want to automate this,
    <
        CompHolder<CompBase::INPUT>,
        CompHolder<CompBase::GRAPHICS>
    > compHolders;
};

class CompHandler
{
    // ...
private:
    std::tuple // and this process, based on the predefined array
    <
        CompCont<CompBase::INPUT>,
        CompCont<CompBase::GRAPHICS>
    > compContainers;
};

据我了解,std::make_tuplec++14 ref 之前甚至不是 constexpr 所以我不确定这是否可能,因为我需要一个c++11 方法。我认为数组的存在是强制性的,因为单独的枚举并不能为这样的事情提供必要的功能。

【问题讨论】:

  • 用类型列表替换你的枚举怎么样?那么以后使用起来真的会更容易。恕我直言,有枚举来列出“类型”是很差的,可变参数模板就在这里。
  • 它可能很差,但我得到了相当不错的功能,而且更容易实现;虽然是的,但我遇到了一些问题。我以前使用过可变参数模板,实际上我认为它们不会使事情比这更干净,或者更可扩展(如果它有效,我当然对此非常开放)。
  • 既然您似乎不介意必须编写两次枚举器列表(这是您要在此处自动化的第三个副本),那么您可以保留 enum 并替换 array使用可变参数模板的实例化,您可以从中获得所需的自动化。这听起来像一个解决方案吗?
  • 否则,问题不在于make_tuple,而在于array:它的 const 访问器仅在 C++14 中使用 constexpr,所以在 C++11 中你不能获取这些数组元素并使用它们来构建类型 - 它们不会被接受为非类型模板参数。
  • @bogdan 哦,我明白了。我会研究那个方法,谢谢。

标签: c++ arrays c++11 tuples metaprogramming


【解决方案1】:

这是一个适用于 C++11 的解决方案。正如 cmets 中所讨论的,使用 std::array 可以在 C++14 中工作,其中它的 const 访问器是 constexpr

#include <tuple>
#include <type_traits>
#include <iostream>

class CompBase
{
public:
   enum CompType {
      INPUT,
      GRAPHICS
      // ( + 5-10 additional types)
   };
};

template<CompBase::CompType...> struct CTLHelper;
using CompTypeList = CTLHelper<
   CompBase::INPUT,
   CompBase::GRAPHICS
>;

template<template<CompBase::CompType> class, class> struct CompTupleMaker;
template<template<CompBase::CompType> class H, CompBase::CompType... Es> 
struct CompTupleMaker<H, CTLHelper<Es...>>
{
   using type = std::tuple<H<Es>...>;
};

template<CompBase::CompType compType_e>
class CompHolder {}; // owns one component

template<CompBase::CompType compType_e>
class CompContainer {}; // references N components

using CompHolderTuple = CompTupleMaker<CompHolder, CompTypeList>::type;
using CompContainerTuple = CompTupleMaker<CompContainer, CompTypeList>::type;

class CompInterface
{
   // ...
private:
   CompHolderTuple compHolders;
};

class CompHandler
{
   // ...
private:
   CompContainerTuple compContainers;
};


int main()
{
   // just a quick check
   std::cout << std::is_same<CompHolderTuple, std::tuple<CompHolder<CompBase::INPUT>, CompHolder<CompBase::GRAPHICS>>>::value << '\n';
}

如果你真的需要 C++11 中的数组中的这些枚举器,你可以使用声明为 constexpr 的内置数组 - 你可以在常量表达式中引用它的元素。我想说这只有在您还需要该数组来做其他事情时才有意义;如果您只需要一个枚举器列表的持有者,那么在这种情况下,可变参数解决方案更简单。对于数组解决方案,您需要类似于 C++14 的 std::index_sequence 来扩展数组。

【讨论】:

  • 请问,如果传递了non-CompType 参数,您是否使用类型的第二个模板参数声明CompTupleMaker 以调用编译器警告,还是有其他原因?
  • @AromaticCodeProducer CompTupleMaker 的第二个参数是保存CompType 枚举器列表的类型(在用于创建它的模板参数中)。我们需要将该列表作为参数包传入,以便在构建 tuple 专业化时扩展一些内容。 CompTupleMaker的部分特化解决了这个问题。如果传入 CTLHelper 的特化以外的任何其他内容,它确实也确保我们得到编译器错误,因为这将尝试实例化未定义的主模板。
  • @AromaticCodeProducer(可以使用包含static_assert 的主体定义主模板,以便在这种情况下提供更好的编译时错误消息。)无论如何,我不确定是否这回答了你的问题。如果没有,请告诉我,我们可以进一步讨论。
  • 我明白了,部分专业化的潜力比我之前想象的要大得多,非常有趣。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-14
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
  • 1970-01-01
  • 1970-01-01
  • 2016-09-03
相关资源
最近更新 更多