www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Implicit Function Template Instantiation (IFTI) Question

reply jmh530 <john.michael.hall gmail.com> writes:
When using a template with multiple functions within it, is it 
possible to access the underlying functions directly? Not sure I 
am missing anything, but what works when the functions are named 
differently from the headline template doesn't work when the 
functions are named the same.

import std.stdio: writeln;
import std.traits: isFunction;

template foo(T) {
     void foo(U)(U x) {
         writeln("here0");
     }

     void foo(U, V)(U x, V y) {
         writeln("there0");
     }
}

template bar(T) {
     void baz(U)(U x) {
         writeln("here1");
     }

     void baz(U, V)(U x, V y) {
         writeln("there1");
     }
}

void foobar(T)(T x) {}

void main() {
     foo!int.foo!(float, double)(1f, 2.0); //Error: template 
foo(U)(U x) does not have property foo
     writeln(isFunction!(foo!int)); //prints false, as expected 
b/c not smart enough to look through
     writeln(isFunction!(foo!int.foo!float)); //Error: template 
identifier foo is not a member of template 
onlineapp.foo!int.foo(U)(U x)
     writeln(isFunction!(foo!int.foo!(float, double))); //ditto

     bar!int.baz!(float, double)(1f, 2.0); //prints there1
     writeln(isFunction!(bar!int.baz!(float, double))); //prints 
true

     writeln(isFunction!(foobar!int)); //prints true
}
Apr 27 2020
next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 4/27/20 1:19 PM, jmh530 wrote:
 When using a template with multiple functions within it, is it possible 
 to access the underlying functions directly? Not sure I am missing 
 anything, but what works when the functions are named differently from 
 the headline template doesn't work when the functions are named the same.
 
 import std.stdio: writeln;
 import std.traits: isFunction;
 
 template foo(T) {
      void foo(U)(U x) {
          writeln("here0");
      }
 
      void foo(U, V)(U x, V y) {
          writeln("there0");
      }
 }
 
 template bar(T) {
      void baz(U)(U x) {
          writeln("here1");
      }
 
      void baz(U, V)(U x, V y) {
          writeln("there1");
      }
 }
 
 void foobar(T)(T x) {}
 
 void main() {
      foo!int.foo!(float, double)(1f, 2.0); //Error: template foo(U)(U x) 
 does not have property foo
foo!int aliases to the template foo's inside, so you are already in there. In reality, you should want to use foo!int!(float, double), but that does not parse. You can do: alias x = foo!int; x!(float, double)(...) or you can just use IFTI: foo!int(1f, 2.0);
      writeln(isFunction!(foo!int)); //prints false, as expected b/c not 
 smart enough to look through
No, because the template hasn't been instantiated. Note that isFunction!(foobar) prints false also.
      writeln(isFunction!(foo!int.foo!float)); //Error: template 
 identifier foo is not a member of template onlineapp.foo!int.foo(U)(U x)
An eponymous template is equivalent to the members that have the same name. There is no way to access the template namespace (this was changed some time ago). with x definition above: writeln(isFunction!(x!float)); // true
      writeln(isFunction!(foo!int.foo!(float, double))); //ditto
 
      bar!int.baz!(float, double)(1f, 2.0); //prints there1
      writeln(isFunction!(bar!int.baz!(float, double))); //prints true
 
      writeln(isFunction!(foobar!int)); //prints true
 }
 
 
Generally it's just fine to do foo(T, U, V) and dispense with the double templates, as IFTI will take care of the other two. The main reason to have nested templates is when you need to bind the explicit template parameters to a variadic, and the IFTI parameters to something else. i.e.: template foo(T...) { void foo(U...)(U args) {... } } foo!(int, char, bool)(1, 2, 3) -> foo!(int, char, bool)!(int, int, int)(1, 2, 3); I hope this clears it up a bit. -Steve
Apr 27 2020
parent jmh530 <john.michael.hall gmail.com> writes:
On Monday, 27 April 2020 at 17:40:06 UTC, Steven Schveighoffer 
wrote:
 [snip]
Thanks for that. Very detailed. In terms of a use case, we just added a center function to mir [1]. It can take an alias to a function. I wanted to add a check that the arity of the function was 1, but it turned out that I couldn't do that for mean [2] because it has a similar structure as what I posted and arity relies on isCallable, which depends on isFunction.
Apr 27 2020
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Apr 27, 2020 at 05:19:35PM +0000, jmh530 via Digitalmars-d-learn wrote:
 When using a template with multiple functions within it, is it
 possible to access the underlying functions directly?
Yes, but only if the template is not eponymous.
 Not sure I am missing anything, but what works when the functions are
 named differently from the headline template doesn't work when the
 functions are named the same.
Yes, when the template is eponymous, the name of the template becomes the name of the eponymous member, and thus effectively hides the other members from outside access. This is actually useful when you want to write a template function with internal implementation details that outside code cannot access no matter what. It's like a little encapsulation unit locked away behind the public-facing eponymous member. I've used this on a few occasions when I wanted template implementation details to be invisible even to other code inside the same module. (Interesting note: you can even stick unittests inside the template block to test internal details, while still keeping said details away from prying eyes in the rest of the module. :-P) T -- Doubtless it is a good thing to have an open mind, but a truly open mind should be open at both ends, like the food-pipe, with the capacity for excretion as well as absorption. -- Northrop Frye
Apr 27 2020