On Thu, Jul 29, 2010 at 22:40, Jason Spencer <spenc...@sbcglobal.net> wrote:
> In writing templates that make heavy use of alias parameters, does > anyone else feel uneasy about whether the caller will pass a type, a > value, or a schmoo? I thought they could only be symbols. That is, an alias is a 'link', a sort of pointer to a symbol: a template name, a module name, a function name, etc. It does not seem to accept types: template TestAlias(alias a) { enum string TestAlias = __traits(identifier, a); } void main() { T foo(T)(T t) { return t;} writeln(TestAlias!foo); // works writeln(TestAlias!int); // do not compile } Though '3' is accepted by alias... Hmm. > I'm having a hard time getting my head around > how wide-open aliases are and trying to resist the urge to put in > thousands of static asserts to check what should be invariants on > the kind of thing that can be passed in that position. This all > feels very strange when I typically look for templates to provide > that nice, static, compile-time safety that keeps me from having to > check everything that gets passed. Any words of wisdom on adjusting > to this feature? Wisdom, I don't know, as I still feel like I'm exploring things. But template constraints are there to limit what you can instantiate. The C++ syntax is still there (T : U, etc), but it's quite limited and not so easy to parse, compared to D template constraints. Feel free to ignore what follows if that's well-treaded ground to you. Say I have a template that takes an alias, fun, and a type, T. fun is supposed to be a function, but in fact why limit it to that? What I need is for foo to be callable with a T. So let's test for that: auto doSomething(alias fun, T)(T t) if (is(typeof( fun(T.init) ))) { // now that I'm here, I can freely use fun as a callable on any T auto result = fun(t); // ... } So, T is a type. T.init is a value of type T, the default value for any T. .init is a easy way to generate a value from a type. Any type in D has a .init field (not typetuples, though). Note that 't' is not really accessible inside the constraint template, because t will have a runtime value, whereas here we are at compile-time. I think t can be used, but is still T.init at this stage. I call fun with T.init. If that compiles, then the resulting expression has a type: I use typeof() to get it, and then the is() expression to get a bool telling me if that's a valid type. If foo(T.init) doesn't compile, for whatever reason (fun as no opCall defined, or foo is callable, but not with a T...) then foo(T.init) has no type, so is(typeof( ... )) returns false and the template constraint forbids the template to be instantiated. inside doSomething(), I can freely use fun as something callable with one T. Note that my constraint is not complete: I did not test for fun(T.init) to return a value: it could be a void function(T) and the assignement would fail. I could also test for that, I guess. Philippe