Working on a parser combinator library, and I want to limit the types of things my combinators will accept. They have to be a "parser" which basically means they're convertible to a parser class that's a thin wrapper generally. I am, however, having trouble stating that through the type system. This is a dissected example:
#include <string>
#include <functional>
#include <type_traits>
using namespace std;
// parser can be built from a certain callable
template <typename P,
typename enable_if<
is_convertible<P, function<bool(string)>>::value
>::type* = nullptr
>
struct parser {
parser(P p)
: p_(p) {}
// just call contained parser
bool operator()(string stream) {
return p_(stream);
}
private:
P p_;
};
// type function to validate that a type is a parser
template <typename A, typename B=void>
using is_parser =
std::enable_if<
std::is_convertible<A, parser<A>>::value &&
(std::is_convertible<B, parser<B>>::value || std::is_void<B>::value)
>;
// invert result of parser
template <typename A, typename is_parser<A>::type* = nullptr>
struct notparser {
notparser(A p)
: p_(p) {}
bool operator()(string stream) {
return !p_(stream);
}
private:
parser<A> p_;
};
// not operator
template <typename A, typename is_parser<A>::type* = nullptr>
notparser<A> operator !(A a) {
return notparser<A>(a);
}
Even without instantiating anything, or even a main function, this generates an error in g++ 5.4.0:
test.cc: In substitution of ‘template<class A, class B> using is_parser = std::enable_if<(std::is_convertible<A, parser<A> >::value && (std::is_convertible<B, parser<B> >::value || std::is_void<_Arg>::value))> [with A = A; B = void]’:
test.cc:38:43: required from here
test.cc:33:48: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
(std::is_convertible<B, parser<B>>::value || std::is_void<B>::value)
^
test.cc:33:48: note: invalid template non-type parameter
The only weirdness I see is the substitution into is_parser with A=A, is this a template-expansion-phase thing?
Aucun commentaire:
Enregistrer un commentaire