1 /**
2 *   Copyright: © 2014-2015 Anton Gushcha
3 *   License: Subject to the terms of the Boost 1.0 license as specified in LICENSE file
4 *   Authors: Anton Gushcha <ncrashed@gmail.com>
5 *
6 *   Template for detecting overloads - extension of std.traits;
7 */
8 module stribog.meta.overload;
9 
10 import std.traits : isCallable, staticIndexOf, ReturnType, hasMember, ParameterTypeTuple;
11 
12 import stribog.meta.base;
13 import stribog.meta.satisfy;
14 import stribog.meta.map;
15 
16 /**
17 *   Variant of std.traits.hasMember that checks also by member type
18 *   to handle overloads.
19 *   
20 *   $(B T) is a type to be checked. $(B ElemType) is a member type, and 
21 *   $(B ElemName) is a member name. Template returns $(B true) if $(B T) has
22 *   element (field or method) of type $(B ElemType) with name $(B ElemName).
23 *
24 *   Template returns $(B false) for non aggregates.
25 */
26 template hasOverload(T, ElemType, string ElemName)
27 {
28     static if(is(T == class) || is(T == struct) || is(T == interface) || is(T == union))
29     {
30         static if(isCallable!ElemType)
31         {
32             alias retType = ReturnType!ElemType;
33             alias paramExpressionList = ParameterTypeTuple!ElemType;
34             
35             private template extractType(alias F)
36             {
37                 alias extractType = typeof(F);
38             }
39             
40             static if(hasMember!(T, ElemName))
41                 alias overloads = staticMap!(extractType, __traits(getOverloads, T, ElemName));
42             else
43                 alias overloads = ExpressionList!();
44             
45             /// TODO: at next realease check overloads by attributes
46             //pragma(msg, __traits(getFunctionAttributes, sum));
47             
48             private template checkType(F)
49             {
50                 static if(is(ReturnType!F == retType))
51                 {
52                     enum checkType = staticEqual!(StrictExpressionList!(ParameterTypeTuple!F), StrictExpressionList!(paramExpressionList));
53                 } else
54                 {
55                     enum checkType = false;
56                 }
57             }
58             
59             enum hasOverload = anySatisfy!(checkType, overloads);
60         }
61         else
62         {
63             enum hasOverload = staticIndexOf!(ElemName, __traits(allMembers, T)) != -1 &&
64                 is(typeof(__traits(getMember, T, ElemName)) == ElemType);
65         }
66     }
67     else
68     {
69         enum hasOverload = false;
70     }
71 }
72 /// Example
73 unittest
74 {
75     struct A
76     {
77         bool method1(string a);
78         bool method1(float b);
79         string method1();
80         
81         string field;
82     }
83     
84     static assert(hasOverload!(A, bool function(string), "method1"));
85     static assert(hasOverload!(A, bool function(float), "method1"));
86     static assert(hasOverload!(A, string function(), "method1"));
87     static assert(hasOverload!(A, string, "field"));
88     
89     static assert(!hasOverload!(A, bool, "field"));
90     static assert(!hasOverload!(A, void function(), "method1"));
91     static assert(!hasOverload!(A, bool function(), "method1"));
92     static assert(!hasOverload!(A, string function(float), "method1"));
93     
94     /// TODO: at next realease check overloads by attributes
95 //    struct D
96 //    {
97 //        string toString() const {return "";}
98 //    }
99 //    
100 //    static assert(hasOverload!(D, const string function(), "toString"));
101 //    static assert(!hasOverload!(D, string function(), "toString"));
102 }