1 /*******************************************************************************
2 
3     Copyright:
4         Copyright (C) 2017 dunnhumby Germany GmbH. All rights reserved.
5 
6     License:
7         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
8         Alternatively, this file may be distributed under the terms of the Tango
9         3-Clause BSD License (see LICENSE_BSD.txt for details).
10 
11 *******************************************************************************/
12 
13 module ocean.meta.types.Templates;
14 
15 /*******************************************************************************
16 
17     Emulates `static if (Type : Template!(Args), Args...)`, which is a D2
18     feature
19 
20     Given a template and an instance of it, allows to get the arguments used
21     to instantiate this type.
22 
23     An example use case is when you want to wrap an aggregate which is templated
24     and need your `Wrapper` class to be templated on the aggregate's template
25     arguments:
26     ---
27     class Wrapper (TArgs...) { /+ Magic stuff +/ }
28     class Aggregate (TArgs...) { /+ Some more magic +/ }
29 
30     Wrapper!(TemplateInstanceArgs!(Aggregate, Inst)) wrap (Inst) (Inst i)
31     {
32         auto wrapper = new Wrapper!(TemplateInstanceArgs!(Aggregate, Inst))(i);
33         return wrapper;
34     }
35     ---
36 
37     This can also be used to see if a given symbol is an instance of a template:
38     `static if (is(TemplateInstanceArgs!(Template, PossibleInstance)))`
39 
40     Note that eponymous templates can lead to surprising behaviour:
41     ---
42     template Identity (T)
43     {
44         alias T Identity;
45     }
46 
47     // The following will fail, because `Identity!(char)` resolves to `char` !
48     static assert(is(TemplateInstanceArgs!(Identity, Identity!(char))));
49     ---
50 
51     As a result, this template is better suited for template aggregates,
52     or templates with multiple members.
53 
54     Params:
55         Template = The template symbol (uninstantiated)
56         Type     = An instance of `Template`
57 
58 *******************************************************************************/
59 
60 public template TemplateInstanceArgs (alias Template, Type : Template!(TA), TA...)
61 {
62     public alias TA TemplateInstanceArgs;
63 }
64 
65 version (unittest)
66 {
67     private class BaseTestClass (T) {}
68     private class DerivedTestClass (T) : BaseTestClass!(T) {}
69 }
70 
71 unittest
72 {
73     // Same type
74     static assert (is(TemplateInstanceArgs!(BaseTestClass, BaseTestClass!(int[]))));
75     // Derives
76     static assert (is(TemplateInstanceArgs!(BaseTestClass, DerivedTestClass!(int))));
77     // Not a template
78     static assert (!is(TemplateInstanceArgs!(Object, BaseTestClass!(int))));
79     // Not a type
80     static assert (!is(TemplateInstanceArgs!(BaseTestClass, BaseTestClass)));
81     // Doesn't derive / convert
82     static assert (!is(TemplateInstanceArgs!(int, BaseTestClass)));
83 }
84