1

In the tutorial is exersize, where need:

add error checking to the binary template causes a compilation error if N contains digits other than 0 or 1

It is enough simple to do it by standard features:

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

But how to do it by mpl::vector_c? For example:

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 Answers 2

2

Partial template specialization might help you here:

The trick is to first define the template the way you use it (with an int (N) and the type (which will be the mpl::vector_c), and to then 'break it down' into the components you want to obtain access to (in this case two integers of which the vector_c is comprised). Below you can find the example which works for a vector_c with exactly two parameters. You can also extend this to work with an arbitrary amount of parameters (which might be a fun second exercise :) and could be achieved using a parameter pack).

#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;
}

Related Links you might find interesting:

Note that this solution does not work with standards <= c++03

Sign up to request clarification or add additional context in comments.

Comments

2

Building on top of the other answer, below you can find a solution using SFINAE as indicated in the question by the use of enable_if.

This is somewhat more tricky than I originally expected it to be, because somehow the amount of provided arguments for the boost::mpl_vector_c in the partial template specialization does not match the size of the mpl::vector.

Therefore, I define a helper struct below which allows to perform the boolean 'and' operation on a subset of a provided variadic template of boolean values.

If c++17 is available, the lines marked by the comment c++14/c++17 can be excanged. If c++14 is not available, the the index_sequence can for instance be replaced by making use of a recursive #value declaraion in the struct and _v/_t suffixes replaced by [...]::value/type respectively.


#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;
}

The code example can be found here in CompilerExplorer.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.