Как проверить значения в mpl :: vector_ c? - PullRequest
1 голос
/ 01 марта 2020

В учебник является exersize, где необходимо:

добавление проверки ошибок в двоичный шаблон вызывает ошибку компиляции, если N содержит цифры, отличные от 0 или 1

Достаточно просто сделать это стандартными функциями:

template <int N>
struct Binary {
  static_assert(N == 0 || N == 1, "binary have to be 0 or 1");
  const int n = N;
};

Но как это сделать с помощью mpl :: vector_ c? Например:

using values = mpl::vector_c<int, 0, 1>;

template<int N,
         typename = typename std::enable_if</*TODO compare N with values from mpl::vector_c*/>::type>
struct Binary {
  const int n = N;
};

Ответы [ 2 ]

2 голосов
/ 22 марта 2020

Построение поверх другого ответа , ниже вы можете найти решение с использованием SFINAE, как указано в вопросе с использованием enable_if.

Это несколько сложнее, чем Первоначально я ожидал, что это так, потому что количество предоставленных аргументов для boost::mpl_vector_c в частичной специализации шаблона не соответствует размеру mpl::vector.

. Поэтому я определяю вспомогательную структуру, ниже которой позволяет выполнять логические операции 'и' над подмножеством предоставленного шаблона логических значений переменной c.

Если доступен c ++ 17, строки, помеченные комментарием c ++ 14 / c ++ 17 можно исключить. Если c ++ 14 недоступен, index_sequence может, например, быть заменен путем использования рекурсивного объявления #value в структуре и суффиксов _v / _t, замененных на [...]::value/type соответственно.


#include <boost/mpl/vector_c.hpp>

#include <tuple>

/// Helper struct which enables to evaluate a conjunction of a subset of a set of booleans.
template <typename IndexSequence, bool... v> struct PartialConjunction;
/// Parital template specialization
template <std::size_t... idx, bool... b>
struct PartialConjunction<std::index_sequence<idx...>, b...>
    : std::integral_constant<
          bool, (std::get<idx>(std::forward_as_tuple(b...)) && ...)> {};
/// 'Alias' for the value 
template <std::size_t S, bool... v> constexpr auto PartialConjunction_v =
    PartialConjunction<decltype(std::make_index_sequence<S>()), v...>::value;


/// Actual struct which holds the type of the vector in ::type if it meets the criterion
template <typename VecType, VecType N, typename MplVector> struct Same; //< c++14
//template <auto N, typename MplVector> struct Same;                    //< c++17
template <typename VecType, VecType N, long... a> struct Same<VecType, N, boost::mpl::vector_c<VecType, a...>> {// c++14
//template <typename VecType, VecType N, long... a> struct Same<N, boost::mpl::vector_c<VecType, a...>> {       // c++17
  using type = boost::mpl::vector_c<VecType, a...>;
  static constexpr auto Size = typename type::size();
  static constexpr auto value = PartialConjunction_v<Size, N == static_cast<VecType>(a)...>;
};
/// Alias for the type which performs SFINAE.
template <typename T, T N, typename VectorType, typename = std::enable_if_t<Same<T, N, VectorType>::value>>  // c++14..
using Same_t = typename Same<T, N, VectorType>::type;
//template <auto N, typename VectorType, typename = std::enable_if_t<Same<N, VectorType>::value>>            // c++17..
//using Same_t = typename Same<N, VectorType>::type;



int main() {

  // For the c++17 version, the first 'int' in the parameter list can be omitted

  //Same_t<int, 1, boost::mpl::vector_c<int, 1, 1, 2>> fails;

  Same_t<int, 1, boost::mpl::vector_c<int, 1, 1, 1>> ok;
  Same_t<int, 1, boost::mpl::vector_c<int, 1, 1>> okok;
  Same_t<int, 1, boost::mpl::vector_c<int, 1>> okokok;
}

Пример кода можно найти здесь в CompilerExplorer.

1 голос
/ 01 марта 2020

Частичная специализация шаблона может помочь вам в этом:

Хитрость заключается в том, чтобы сначала определить шаблон, как вы его используете (с помощью int (N) и типа (который будет mpl :: vector_ *) 1023 *), а затем «разбить его» на компоненты, к которым вы хотите получить доступ (в данном случае два целых числа, из которых состоит вектор_ c). Ниже вы можете найти пример, который работает для вектора_ c с двумя параметрами. Вы также можете расширить это для работы с произвольным количеством параметров (что может быть забавным вторым упражнением :) и может быть достигнуто с помощью пакета параметров).

#include <boost/mpl/vector_c.hpp>

using namespace boost;
using values = mpl::vector_c<int, 1, 1>;

template <int N, typename T> struct Binary;
template <int N, typename t, long a, long b> struct Binary<N, boost::mpl::vector_c<t, a, b>> {
  static_assert(N == a && b == N, "invalid vector_c");
};

int main() {
  //Binary<1, boost::mpl::vector_c<int, 1, 2>> koo; // commented out as assertion fails
  Binary<1, values> kooo;
}

Ссылки, которые могут вас заинтересовать:

Обратите внимание, что это решение не работает со стандартами <= c ++ 03 </p>

...