【问题标题】:Variadic Template Parameter Packs with Alternating Types具有交替类型的可变参数模板参数包
【发布时间】:2015-08-09 19:53:56
【问题描述】:

我想知道是否可以使用参数包捕获交替参数模式。例如,

template<typename T, size_t U, typename... Args>
class foo<T, U, Args...>
{
   public:
     foo() : my_T(nullptr), my_U(U) {}

   private:
     T* my_T;
     size_t my_U;
     foo<Args...> my_next_foo;
}

所以这不起作用,因为 Args 是一个只有类型的参数包。有没有办法修改它,以便可以在可变参数模板中正确捕获 typename T, size_t U 模式?谢谢

【问题讨论】:

  • 是的。将类型和值对作为类型列表。
  • 一般来说(当你的模式不重复时),传输非类型参数的常用方法是将它们放在一个类中。示例包括std::true_typestd::integral_constant 等。

标签: c++ c++11 variadic-templates


【解决方案1】:

根据我的经验,作为模板参数的值是二等公民。

使用别名将它们升级为头等舱:

template<std::size_t n>
using size = std::integral_constant<std::size_t, n>;

然后模式匹配:

template<class...>
struct foo;
template<>
struct foo<> {
  // empty
};
template<class T, size_t U, typename... Args>
struct foo<T, size<U>, Args...> {
  foo() : my_T(nullptr), my_U(U) {}

private:
  T* my_T;
  size_t my_U;
  foo<Args...> my_next_foo;
};

鲍勃是你的叔叔。

但请注意,将 U 作为模板参数,然后将其存储为运行时值是非常值得怀疑的。

foo的用户必须这样做:

foo< Chicken, size<3>, Dog, size<17> >

而不是

foo< Chicken, 3, Dog, 17 >

【讨论】:

  • 这似乎是迄今为止最好的选择。一个问题,存储模板参数以供在运行时使用会有什么缺陷?
  • @armstrhu 您可以在运行时访问它们而无需存储它们。 enum {my_U=U}; 让您可以相对轻松地从 foo&lt;?&gt; 类型访问 U 的编译时值。这是一个坏信号的原因是,如果你有一个在运行时变化的值,为什么不将它作为运行时值传入,而不是在类型中编码呢?
  • 啊,好点。所以你是对的,对于我的应用程序,我实际上不需要存储 U 的值,只需访问它。我想在我上面的小例子中,我并没有完全考虑到这一点。基本上,我在一组 std::array 上构建一个可变参数模板,我试图弄清楚如何传递数组类型和长度。所以真的,我的 T* 实际上是一个 std::array* 并且不会有 size_t U 变量。无论如何,您的解决方案应该可以解决我的问题。谢谢
【解决方案2】:

当然,写你自己的一对:

template <typename T, size_t U>
struct foo_pair { };

还有这些:

template<typename T, size_t U, typename... Pairs>
class foo<foo_pair<T, U>, Pairs...> {
    ...
};

实例化如下:

foo<foo_pair<int, 4>, foo_pair<char, 17>, ...> f;

【讨论】:

    【解决方案3】:

    您可以将Args 传递给foo 作为std::tuple。将std::integral_constant 用于U,而不是将整数常量作为模板参数传递给std::tuple。然后Args 参数包包含所有类型和大小对。

    例如,在实例化 foo 时,您会使用如下类型:

    Foo<std::tuple<int, std::integral_constant<size_t, 5> >,
        std::tuple<char, std::integral_constant<size_t, 3> > >
    

    在实现foo 时,您应该将参数包传递给另一个std::tuple 并使用std::tuple_element 选择元组的第N 个元素。

    这只是一种可能的方法,如果您使用类型列表,您可能会发现实现foo 会更容易。

    【讨论】:

    • tuple 这种方式的一个问题是它是一个大而复杂的类,以使实例在运行时处于最佳状态。仅将其用作将类型打包在一起的一种方式可能会导致编译器不必要地变得笨拙。
    【解决方案4】:

    您可以使用size_t my_U 创建一个表示数据容器T* my_T 的类。有了它,你就可以实现你的模板了:

    #include <array>
    
    using std::size_t;
    
    template<typename... Args>
    struct foo;
    
    template<typename T, size_t N>
    struct foo<std::array<T, N>>
    {
        std::array<T, N> array;
    };
    
    template<typename T, size_t N, typename... Args>
    struct foo<std::array<T, N>, Args...>
    {
        std::array<T, N> array;
        foo<Args...> next_array;
    };
    
    int main() {
        foo<std::array<char, 1>, std::array<short, 2>, std::array<int, 4>> foos;
    }
    

    注意:我使用 std::array 作为数据容器的替代品。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-27
      • 2019-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多