【问题标题】:Create a variadic template from a constexpr array从 constexpr 数组创建可变参数模板
【发布时间】:2014-12-21 12:57:08
【问题描述】:

假设我们有以下类型

template <bool... Values>
struct foo{};

我想从 constexpr 数组 bool tab[N] 创建一个可变参数模板。换句话说,我想做这样的事情:

constexpr bool tab[3] = {true,false,true};
using ty1 = foo<tab[0], tab[1], tab[2]>;

但我想以编程方式进行。目前,我尝试了以下方法:

template <std::size_t N, std::size_t... I>
auto
mk_foo_ty(const bool (&tab)[N], std::index_sequence<I...>)
{
  // error: template argument for template type parameter must be a type
  return foo<tab[I]...>{};
}

// error (see mk_foo_ty)
using ty2 = decltype(mk_ty(tab, std::make_index_sequence<3>{}));

// error: expected '(' for function-style cast or type construction
using ty3 = foo<(tab[std::make_index_sequence<3>])...>;

我什至不确定这是否可能。也许诉诸 Boost.Preprocessor 之类的东西,但我不喜欢这个主意。那么,有人有想法吗?谢谢!

编辑

一方面我有一个constexpr 布尔方阵的框架,可以在编译时使用异或、否定等创建。

另一方面,我有一个模板框架,它使用以布尔值作为参数的可变参数模板中编码的信息静态创建操作。

我的目标是弥合这两个框架之间的差距。因此,我不能使用硬编码的解决方案。

编辑 2

我发现这个question 有同样的问题和一个很好的答案,它非常接近T.C.'s one(使用指针)。 extern 链接也很重要。

但是,我意识到我忘记了一个关键元素。我的bool 数组包含在matrix 结构中,以便能够重载运算符^、| 等:

template <std::size_t N>
struct matrix
{
  const bool data_[N*N];

  template<typename... Values>
  constexpr matrix(Values... values) noexcept
    : data_{static_cast<bool>(values)...}
  {}

  constexpr bool operator [](std::size_t index) const noexcept
  {
    return data_[index];
  }
}

因此,如果我们应用 T.C 的解决方案:

template<std::size_t N, const bool (&Tab)[N], class>
struct ty1_helper;

template<std::size_t N, const bool (&Tab)[N], std::size_t... Is>
struct ty1_helper<N, Tab, std::index_sequence<Is...>>
{
  using type = foo<Tab[Is]...>;
};

template<std::size_t N, const bool (&Tab)[N]>
using ty1 = typename ty1_helper<N, Tab, std::make_index_sequence<N>>::type;

编译器抱怨传递非类型参数:

// error: non-type template argument does not refer to any declaration
//        using t = make_output_template<m.data_, std::make_index_sequence<3>>;
//                                       ^~~~~~~
using t = ty1<3, m.data_>;

【问题讨论】:

  • 你想推多远?可以硬编码tab 及其大小还是想要更通用的东西?
  • 您使用哪种语言? C++11 还是 C++14? (对我来说,它看起来很像后者......)
  • 您在寻找the indices trick吗?
  • @LightnessRacesinOrbit 我在此示例中使用 C++14 来简化索引的创建,但它可以在 C++11 中使用适当的替换。

标签: c++ c++11 c++14


【解决方案1】:

我在上面的 cmets 中使用带有外部链接的全局 constexpr 变量(由于 GCC 的不符合外部链接要求,请参阅 bug 52036),如果你把它在标题中,并将标题包含在不同的翻译单元中。仅对一个翻译单元有用的解决方案并不是什么解决方案。一种解决方法是将矩阵存储为类的静态数据成员。

struct matrix_holder {
    static constexpr matrix<2> mat = {true, false, true, false};
};

template<std::size_t N, const matrix<N> &Mat, class> 
struct ty1_helper;

template<std::size_t N, const matrix<N> &Mat, std::size_t... Is>
struct ty1_helper<N, Mat, std::index_sequence<Is...>> { 
    using type = foo<Mat[Is]...>; 
};

template<std::size_t N, const matrix<N> &Mat>
using ty1 = typename ty1_helper<N, Mat, std::make_index_sequence<N*N>>::type;

static_assert(std::is_same<ty1<2, matrix_holder::mat>,
                           foo<true, false, true, false>>::value, "Oops");

Demo。此外,由于在 ty1&lt;2, matrix_holder::mat&gt; 中使用 matrix_holder::mat 算作 odr 使用,因此要完全符合要求,您应该提供一个定义:

constexpr matrix<2> matrix_holder::mat;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-07
    • 2013-07-10
    • 2021-12-19
    • 2011-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多