7OON6I5DETIRCQ24MOUVJ5QWQIMPTNP2PCRAA3BFOUMZ3I6PZOKQC
template <auto ...>
struct Term;
// Single item: field (member or method) of _T.
template <typename _T, typename _R, _R(_T::*_field)>
struct Term<_field> {
using Operand = std::decay_t<_T>;
using Result = std::decay_t<std::conditional_t<
std::is_function_v<_R>,
std::invoke_result_t<decltype(_field), _T>,
_R
>>;
constexpr
Result const &operator()(Operand const &operand) const {
if constexpr (std::is_function_v<_R>) {
return (operand.*_field)();
} else {
return operand.*_field;
}
}
};
// Single item: function of _T.
template <typename _T, typename _R, _R(*_function)(_T &)>
struct Term<_function> {
using Operand = std::decay_t<_T>;
using Result = std::decay_t<_R>;
constexpr
Result const &operator()(Operand const &operand) const {
return _function(operand);
}
constexpr
Result const &operator()(Operand &operand) const {
return _function(operand);
}
};
// Multiple items: recursively forward the result of the first term to the remaining ones.
template <auto _head, auto ..._tail>
struct Term<_head, _tail...> {
using Operand = std::decay_t<typename Term<_head>::Operand>;
using Result = typename Term<_tail...>::Result;
constexpr
Result const &operator()(Operand const &operand) const {
return Term<_tail...>{}(Term<_head>{}(operand));
}
constexpr
Result const &operator()(Operand &operand) const {
return Term<_tail...>{}(Term<_head>{}(operand));
}
};
template <auto ..._constraints>
namespace detail {
template <typename ..._Terms> struct operand_f;
template <typename ..._Terms> using Operand = typename operand_f<_Terms...>::value;
template <typename _Head, typename ..._Tail>
struct operand_f<_Head, _Tail...> {
using value = typename _Head::Operand;
};
} // namespace detail
template <typename ..._Terms>
static_assert((std::is_same_v<bool, typename std::decay_t<decltype(_constraints)>::Result> && ...));
using Minterm = std::bitset<sizeof...(_constraints)>;
};
static_assert(
(std::is_same_v<bool, typename std::decay_t<_Terms>::Result> && ...),
"All Constraints must have a Result type of bool"
);
using Operand = detail::Operand<_Terms...>;
using Minterm = std::bitset<sizeof...(_Terms)>;
template <std::size_t _bit, typename _Head, typename ..._Tail>
constexpr
void populate(Minterm &minterm, Operand const &operand, List<_Head, _Tail...>) const {
minterm[_bit] = _Head{}(operand);
if constexpr (sizeof...(_Tail)) {
populate<_bit + 1>(minterm, operand, List<_Tail...>{});
}
}
constexpr
auto fooBarOdd =
Constraints<
Term<&Aggregate::foo, &Foo::value, isOdd>,
Term<&Aggregate::bar, &Bar::value, isEven>
>{};
//
// Assertions
//
template <typename _Term>
struct TermClosure {
_Term term;
typename _Term::Operand operand;
};
template <typename ..._Terms>
bool check(_Terms &&...terms) {
return (std::get<0>(terms)(std::get<1>(terms)) && ...);
}
std::cout << Term<&Foo::value, isOdd>{}(foo) << '\n';
for (int i = 0; i < 10; ++i) {
std::cout << i << ": " << fooBarOdd(Aggregate{Foo{"foo", i}, Bar{i >> 1}}) << '\n';
}
std::cout << check(
std::make_tuple(Term<&Foo::value, isEven>{}, Foo{"foo", 0}),
std::make_tuple(Term<&Foo::value, isOdd >{}, Foo{"foo", 1}),
std::make_tuple(Term<&Foo::value, isEven>{}, Foo{"foo", 2}),
std::make_tuple(Term<&Foo::value, isOdd >{}, Foo{"foo", 3}),
std::make_tuple(Term<&Foo::value, isEven>{}, Foo{"foo", 4}),
std::make_tuple(Term<&Foo::value, isOdd >{}, Foo{"foo", 5}),
std::make_tuple(Term<&Foo::value, isEven>{}, Foo{"foo", 6}),
std::make_tuple(Term<&Foo::value, isOdd >{}, Foo{"foo", 7}),
std::make_tuple(Term<&Foo::value, isEven>{}, Foo{"foo", 8}),
std::make_tuple(Term<&Foo::value, isOdd >{}, Foo{"foo", 9}),
std::make_tuple(Term<&Foo::value, isEven>{}, Foo{"foo", 10})
) << '\n';
: 1
name: cpp-gen
version: 0.0.1
summary: C++ constraint based generator.
type: exe
language: c++
project: cpp-gen
license: MIT
#pragma once
#include <type_traits>
template <auto ...>
struct Term;
// Single item: field (member or method) of _T.
template <typename _T, typename _R, _R(_T::*_field)>
struct Term<_field> {
using Operand = std::decay_t<_T>;
using Result = std::conditional_t<
std::is_function_v<_R>,
std::invoke_result_t<decltype(_field), _T>,
_R const &
>;
constexpr
Result operator()(Operand const &operand) const {
if constexpr (std::is_function_v<_R>) {
return (operand.*_field)();
} else {
return operand.*_field;
}
}
};
// Single item: function of _T.
template <typename _T, typename _R, _R(*_function)(_T &)>
struct Term<_function> {
using Operand = std::decay_t<_T>;
using Result = _R;
constexpr
Result operator()(Operand const &operand) const {
return _function(operand);
}
constexpr
Result operator()(Operand &operand) const {
return _function(operand);
}
};
// Multiple items: recursively forward the result of the first term to the remaining ones.
template <auto _head, auto ..._tail>
struct Term<_head, _tail...> {
using Operand = std::decay_t<typename Term<_head>::Operand>;
using Result = typename Term<_tail...>::Result;
constexpr
Result operator()(Operand const &operand) const {
return Term<_tail...>{}(Term<_head>{}(operand));
}
constexpr
Result operator()(Operand &operand) const {
return Term<_tail...>{}(Term<_head>{}(operand));
}
};
using cxx
cxx.poptions += "-I$src_root/include/"
cxx.coptions += "-Wall" "-Werror"
exe{main} : cxx{src/main.cpp} hxx{include/cpp-gen/Term.h}