-
Notifications
You must be signed in to change notification settings - Fork 78
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mixing polymorphism and templates. #75
Comments
As a follow-up, I realize that C++ requires manual implementation of templates that support variance, so another solution would be an "is convertible-to" pattern or an "is constructible-from" pattern. |
Hi Thomas, Thank you for suggestions. It would really help a lot if you could post some code in ideal syntax or in another language that would show what are you trying to achieve (applicable to both comments). This doesn't have to be what the library or C++ support today. Variance specification would require language support, but if I see the use-case, I might be able to provide you a reasonable solution within the library. |
Assume we have a class hierarchy with inheritance that looks something like this: class Node;
template<class T> class Expr : public Node;
class X : public Expr<X>;
class Y : public X, public Expr<Y>;
class Z : public Expr<Z>;
template<class T> class Let : public Expr<T>;
template<class T> class Symbol : public Expr<T>;
// Some other non-literal expression types I would like to be able to do something like this: template<typename T> bool nodeEvalsToT(Node n){
Match(n) {
Case(C<Expr<T> >(children)) return true;
Otherwise() return false;
} EndMatch
} And have Alternatively, I might like to do something like this: std::string toString(Node n){
Match(n){
Case(C<Let<_> >(bindings, result)) /* something there */
Case(C<Symbol<_> >(boundTo, name)) return name;
// Some other cases
} EndMatch
} Where the I've been thinking about this for a bit, and I think I could actually contort my inheritance hierarchy for this application to make everything work as-is with a bit of hackery: class Node {};
struct AnyVal { typedef AnyVal Super; };
template<typename Super, template<typename D, typename B, typename ...O> class DNode, typename ...O>
using DeriveToBase = typename std::conditional<std::is_same<Super, AnyVal>::value, Node, DNode<Super, typename Super::Super, O...> >::type;
template<class D, typename _Super=AnyVal> class Expr : virtual public DeriveToBase<_Super, Expr> {
typedef _Super Super;
};
template<class T> using _Expr = Expr<T, typename T::Super>; But I haven't gotten to test it yet, and it definitely doesn't feel like a "clean" solution. |
I'm working on a statically type-checked DSL. An expression node of type
T
has typeExpr<T>
, and definition ofT
itself (representing a literal) is something likeclass T : Expr<T>
. There are a handful of Expr-subclasses that still have unbound type parameters (i.e.Let<U,T>
binds variables of typeU
and returns a value of typeT
).I would like to, at a minimum, be able to pattern match over bounded sets of possible
U
andT
without resorting to (manual) copy-paste.The annoying, but reasonably scalable for a small set of types, solution would be a copy-paste macro.
The nice and extensible solution would be some ability to pattern match based on a variance specification for template arguments: if
A
is a subtype ofB
, then being able to match an instance ofExpr<A>
in a pattern that specifiesExpr<B>
would be ideal (in Scala notation, the pattern would be forExpr<+B>
).I suspect I'm not the only person who would like to be able to do something like this, and I'm wondering what the obstacles are to implementation.
The text was updated successfully, but these errors were encountered: