I have an sfinae class that checks if a class is a parser rule (AX parser generator library).
axe::is_rule<P>::valuemust evaluate to true if P satisfies the requirements of the parser rule. The parser rule must have one of the following member functions, taking a pair of iterators and returning axe::result<Iterator>:
template<class Iterator>
axe::result<Iterator> P::operator()(Iterator, Iterator);
or his specialization, or not a template for some type of CharT
axe::result<CharT*> P::operator()(CharT*, CharT*);
or const version above. Theoretically, there may be more than one overloaded operator(), although in practice one single operator()with one of the above signatures is enough .
Unfortunately, the current implementation is_ruleprovides only some, but not all, cases. There are some unsuccessful classes that fail the test is_rule:
static_assert(axe::is_rule<typename std::remove_reference<T>::type>::value, \
"type '"
For example, the following unsuccessful types fail the test:
struct unfortunate
{
axe::result<const unsigned char*>
operator()(const unsigned char*, const unsigned char*);
};
AXE_ASSERT_RULE(unfortunate);
auto unfortunate1 = [](const unsigned char*, const unsigned char*)
->axe::result<const unsigned char*> {};
AXE_ASSERT_RULE(decltype(unfortunate1));
typedef std::vector<char>::iterator vc_it;
struct unfortunate2 { axe::result<vc_it> operator()(vc_it, vc_it) const; };
AXE_ASSERT_RULE(unfortunate2);
typedef axe::result<const char*> (unfortunate3)(const char*, const char*);
AXE_ASSERT_RULE(unfortunate3);
struct rule { template<class I> axe::result<I> operator()(I, I); };
class unfortunate4 : public rule {};
AXE_ASSERT_RULE(unfortunate4);
The current solution in AX is to wrap them in a transport package ( class r_ref_t), which, of course, creates parsing warts (after all, the parser is all about parsing sugar).
How would you modify sfinae's test is_ruleto cover the unfortunate cases above?