在可变参数模板参数上实现数学补充逻辑

时间:2017-10-02 13:34:27

标签: c++ metaprogramming template-meta-programming

我有一个定义constexpr size_t dimensions的类。在本课程中,我实现了EvaluateOver<Dimensions...>(Lambda F),它在我指定的维度上执行了某些操作。例如,假设dimensions=4f是一些lambda表达式:

MyClass.EvaluateOver<0,2>(f);
通过执行以下扩展,

将对0和2执行f

template<size_t... Dims, typename Lambda>
inline auto EvaluateOver(const Lambda& F) const
{
    F(std::get<Dims>(_memberTupleDataContainer)...);
}

现在我想要另一个将评估未指定维度的成员函数。因此EvaluateOverOthers<0,2>(f)将对尺寸1和3执行操作。

理想情况下,我正在考虑以下事项:

template<size_t... Dims, typename Lambda>
inline auto EvaluateOverOthers(const Lambda& F) const
{
    EvaluateOver<
            // variadic parameter that does the mathematical complement of
            // Dims... with a variadic expansion of dimensions
            >(F);
}

2 个答案:

答案 0 :(得分:1)

以下可能有所帮助:

namespace details
{

template <typename Seq1, typename Seq2, typename Res = std::index_sequence<>>
struct minus;

// Nothing more to remove
template <std::size_t ... Is1, std::size_t... IRes>
struct minus<std::index_sequence<Is1...>,
             std::index_sequence<>,
             std::index_sequence<IRes...>>
{
    using type = std::index_sequence<IRes..., Is1...>;
};

// Remove front elements as they are equal.
template <std::size_t I, std::size_t ... Is1, std::size_t ... Is2, std::size_t... IRes>
struct minus<std::index_sequence<I, Is1...>,
             std::index_sequence<I, Is2...>,
             std::index_sequence<IRes...>>
{
    using type = typename minus<std::index_sequence<Is1...>,
                                std::index_sequence<Is2...>,
                                std::index_sequence<IRes...>>::type;
};

// Add front element to result.
template <std::size_t I1, std::size_t I2,
          std::size_t ... Is1, std::size_t ... Is2,
          std::size_t... IRes>
struct minus<std::index_sequence<I1, Is1...>,
             std::index_sequence<I2, Is2...>,
             std::index_sequence<IRes...>>
{
    using type = typename minus<std::index_sequence<Is1...>,
                                std::index_sequence<I2, Is2...>,
                                std::index_sequence<IRes..., I1>>::type;
};

}

template <std::size_t N, typename Seq>
using complement = details::minus<std::make_index_sequence<N>, Seq>;

template <std::size_t N, typename Seq>
using complement_t = typename complement<N, Seq>::type;

// Some test
static_assert(std::is_same<std::index_sequence<0, 3>,
                    complement_t<4, std::index_sequence<1, 2>>>::value, "!");

然后

template<size_t... Is, typename Lambda>
auto EvaluateOver(const Lambda& F, std::index_sequence<Is...>) const
{
    return F(std::get<Is>(_memberTupleDataContainer)...);
}

template<size_t... Dims, typename Lambda>
auto EvaluateOver(const Lambda& F) const
{
    return EvaluateOver(F, std::index_sequence<Is...>{});
}

template<size_t... Is, typename Lambda>
auto EvaluateOverOthers(const Lambda& F) const
{
    return EvaluateOver(F, complement_t<_dimension, std::index_sequence<Is...>>{});
}

答案 1 :(得分:0)

我玩了constexpr C ++ 17解决方案(online demo)。我认为补充的逻辑可以被考虑(如果需要)。

#include <iostream>
#include <iterator>
#include <utility>

#include "my_constexpr_array.hpp"

template<size_t Nd>
struct MyClass {
  static constexpr auto dim_arr = Array(std::make_index_sequence<Nd>{});

  template<size_t... excludes, class F>
  auto eval_others(F f) const {
    constexpr auto excl_arr = Array{excludes...};
    constexpr auto incl_pred = [&] (size_t i) { return !excl_arr.contains(i); };
    constexpr auto incl_excl_arr = dim_arr.partition(incl_pred);
    constexpr auto incl_count = dim_arr.count_if(incl_pred);

    return eval_helper(
      f,
      [&] { return incl_excl_arr; },// wrapped in lambda to preserve constexpr
      std::make_index_sequence<incl_count>{}// indices for trimming incl_excl_arr
    );
  }

  template<class F, class Dims, size_t... is>
  auto eval_helper(F f, Dims dims, std::index_sequence<is...>) const {
    return f(std::integral_constant<size_t, dims()[is]>{}...);
  }
};

int main() {
  MyClass<7> foo{};
  foo.eval_others<2, 4>([&] (auto... is) { (std::cout << ... << is) << "\n"; });
  return 0;
}

my&#34; my_constexpr_array.hpp&#34;会表现得像

template<class T, size_t size>
struct Array {
  static_assert(size >= 1);

  T data_[size];

  constexpr Array() noexcept
  : data_{} {}

  template<class... Ts>
  explicit constexpr Array(T v0, Ts... vs) noexcept
  : data_{v0, vs...} {}

  template<T... vs>
  explicit constexpr Array(std::integer_sequence<T, vs...>) noexcept
    : data_{vs...} {}

  constexpr T* begin() { return data_; }
  constexpr const T* begin() const { return data_; }

  constexpr T* end() { return begin() + size; }
  constexpr const T* end() const { return begin() + size; }

  constexpr decltype(auto) operator[](size_t i) { return data_[i]; }
  constexpr decltype(auto) operator[](size_t i) const { return data_[i]; }

  constexpr bool contains(const T& v) const {
    for(auto& x : *this) if(x == v) return true;
    return false;
  }

  template<class Pred>
  constexpr size_t count_if(Pred pred) const {
    size_t result = 0;
    for(auto& x : *this) result += size_t(pred(x) ? 1 : 0);
    return result;
  }

  template<class Pred>
  constexpr Array partition(Pred pred) const {
// return a sorted copy such that all `true`s precede all `false`s
    Array result{};
    T* true_false_dst[2] = {result.begin(), result.begin() + count_if(pred)};
// pair of output iterators; use first if predicate is true and vice versa
    for(auto& x : *this) *true_false_dst[pred(x) ? 0 : 1]++ = x;
    return result;
  }

  friend std::ostream& operator<<(std::ostream& os, const Array& self) {
    for(auto& x : self) os << x << ", ";
    return os;
  }
};

template<class T, class... Ts>
Array(T, Ts...) -> Array<T, size_t(1) + sizeof...(Ts)>;

template<class T, T... vs>
Array(std::integer_sequence<T, vs...>) -> Array<T, sizeof...(vs)>;