Please consider metafiles like
#include <type_traits> template <typename T, TN, T M> struct Sum : std::integral_constant <T, N + M> {}; template <typename T, TN, T M> struct Product : std::integral_constant <T, N * M> {};
Their result can be extracted through the member ::value :
static_assert (Sum <int, 3, 4>::value == 7, "3 + 4 == 7"); static_assert (Product <int, 2, 5>::value == 10, "2 * 5 == 10");
Both metafiles have the same static signature. That is, they associate a T with each pair T , where T fall under the same restrictions as those imposed by std::integral_constant , and are either summed or multiplied. Therefore, we can create a common metafound for the assessment.
template <typename T, template <typename U, U, U> class F, TN, T M> struct EvaluateBinaryOperator : std::integral_constant <T, F <T, N, M>::value> {}; static_assert (EvaluateBinaryOperator <int, Sum, 3, 4>::value == 7, "3 + 4 == 7"); static_assert (EvaluateBinaryOperator <int, Product, 2, 5>::value == 10, "2 * 5 == 10");
When used exclusively in this form, it seems unnecessary to pollute Sum and Product with the std::integral_constant structure. To show you that we can do without this, consider the following:
template <typename T, TN, TM, TR = N + M> struct Sum; template <typename T, TN, TM, TR = N * M> struct Product; template <typename> struct EvaluateBinaryOperator; template <typename T, template <typename U, U, U, U> class F, TN, TM, T R> struct EvaluateBinaryOperator <F <T, N, M, R> > : std::integral_constant <T, R> {}; static_assert (EvaluateBinaryOperator <Sum <int, 3, 4> >::value == 7, "3 + 4 == 7"); static_assert (EvaluateBinaryOperator <Product <int, 2, 5> >::value == 10, "2 * 5 == 10");
Instead of using the Sum and Product members, we specialize in the default argument and only retrieve it in the EvaluateBinaryOperator . As an added bonus, Sum and Product can be left undefined, making them trivially non-enumerable and non-constructible, and the syntax looks much cleaner. Now, here is the catch. What if we want all of our metafiles to have a single static interface? That is, if you enter
template <typename...> struct Tuple; template <typename T, T> struct Value;
and require all our metafiles to look like template <typename> struct ? For instance,
template <typename> struct Sum; template <typename T, TN, T M> struct Sum <Tuple <Value <T, N>, Value <T, M> > > : std::integral_constant <T, N + M> {}; template <typename> struct Product; template <typename T, TN, T M> struct Product <Tuple <Value <T, N>, Value <T, M> > > : std::integral_constant <T, N * M> {};
Now we would like to convert them into something like:
template <typename, typename> struct Sum; template <typename T, TN, TM, typename R = Tuple <Value <T, N + M> > > struct Sum <Tuple <Value <T, N>, Value <T, M> >, R>; template <typename, typename> struct Product; template <typename T, TN, TM, typename R = Tuple <Value <T, N * M> > > struct Product <Tuple <Value <T, N>, Value <T, M> >, R>;
So we can extract the values โโusing
template <typename> struct Evaluate; template <template <typename, typename> class F, typename I, typename O> struct Evaluate <F <I, O> > { typedef O Type; }; static_assert (std::is_same < Evaluate <Sum <Tuple <Value <int, 3>, Value <int, 4> > > >::Type, Tuple <Value <int, 7> > >::value, "3 + 4 == 7"); static_assert (std::is_same < Evaluate <Product <Tuple <Value <int, 2>, Value <int, 5> > > >::Type, Tuple <Value <int, 10> > >::value, "2 * 5 == 10");
Those of you familiar with the C ++ standard will immediately point out 14.5.5 / 8: "The list of parameters for the specialization template should not contain the default arguments for the template," followed by a tantalizing footnote: "There is no way in which they can be used" . In fact, giving almost any modern compiler, this code gives a compiler error in the specialized Sum and Product templates about violation of the standard. Besides evidence of the above footnote, deprived of the authorโs imagination; we created the right use case for them.
Now you can ask the question: are there other ways to achieve a similar effect when Sum and Product remain undefined / incomplete types, thereby being trivially undetectable and unconstructible, responsible for the operation? Any suggestions are welcome. Thanks in advance.