1[/ 2 (C) Copyright Edward Diener 2011 3 Distributed under the Boost Software License, Version 1.0. 4 (See accompanying file LICENSE_1_0.txt or copy at 5 http://www.boost.org/LICENSE_1_0.txt). 6] 7 8[section:tti_func_templates Introspecting Function Templates] 9 10The one nested element which the TTI library does not introspect is 11function templates. 12 13Function templates, like functions, can be member function templates or 14static member function templates. In this respect they are related to 15functions. Function templates represent a family of possible functions. 16In this respect they are similar to class templates, which represent a 17family of possible class types. 18 19The technique for introspecting class templates in the TTI library is taken 20from the implementation of the technique in the Boost MPL library. In the case 21of `BOOST_TTI_HAS_TEMPLATE` it directly uses the Boost MPL library functionality 22while in the case of `BOOST_TTI_HAS_TEMPLATE_CHECK_PARAMS` it replicates much 23of the technique in the Boost MPL library. The technique depends directly on 24the fact that in C++ we can pass a template as a parameter to another template 25using what is called a "template template" parameter type. 26 27One obvious thing about a template template parameter type is that it is a 28class template. For whatever historical or technical reasons, no one has ever 29proposed that C++ have a way of passing a function template directly as a template 30parameter, perhaps to be called a "function template template" parameter type. 31I personally think this would be a good addition to C++ and would 32make the ability of passing a template as a parameter to another template 33more orthogonal, since both class templates and function templates would be supported. 34My efforts to discuss this on the major C++ newsgroups have 35met with arguments both against its practical usage and the justification 36that one can pass a function template to another template nested in a non-template 37class, which serves as a type. But of course we can do the same thing with class templates, 38which is in fact what Boost MPL does to pass templates as metadata, yet we still have 39template template parameters as class templates. 40 41Nonetheless the fact that we can pass class templates as a template parameter but not 42function templates as a template parameter is the major factor why there is no really good 43method for introspecting function templates at compile time. 44 45[heading Instantiating a nested function template] 46 47There is, however, an alternate but less certain way of introspecting a function template. 48I will endeavor to explain why this way is not currently included in the TTI library, 49but first I will explain what it is. 50 51It is possible to check whether some particular [*instantiation] of a nested function 52template exists at compile-time without generating a compiler error. Although checking if 53some particular instantiation of a nested function template exists at compile-time does 54not prove that the nested function template itself does or does not exist, 55since the instantiation itself may be incorrect and fail even when the nested function 56template exists, it provides a partial, if flawed, means of checking. 57 58The code to do this for member function templates looks like this 59( similar code also exists for static member function templates ): 60 61 template 62 < 63 class C, 64 class T 65 > 66 struct TestFunctionTemplate 67 { 68 typedef char Bad; 69 struct Good { char x[2]; }; 70 template<T> struct helper; 71 template<class U> static Good check(helper<&U::template SomeFuncTemplateName<int,long,double> > *); 72 template<class U> static Bad check(...); 73 static const bool value=sizeof(check<C>(0))==sizeof(Good); 74 }; 75 76where 'SomeFuncTemplateName' is the name of the nested function template, 77followed by some parameters to instantiate it. The 'class C' is the type of 78the enclosing class and the 'class T' is the type of the instantiated member 79function template as a member function. 80 81As an example if we had: 82 83 struct AType 84 { 85 template<class X,class Y,class Z> double SomeFuncTemplateName(X,Y *,Z &) { return 0.0; } 86 }; 87 88then instantiating the above template with: 89 90 TestFunctionTemplate 91 < 92 AType, 93 double (AType::*)(int,long *,double &) 94 > 95 96would provide a compile-time boolean value which would tell us whether the 97nested member function template exists for the particular instantiation 98provided above. Furthermore, through the use of a macro, the TTI library 99could provide the means for specifying the name of the nested member function 100template ('SomeFuncTemplateName' above) and its set of instantiated 101parameters ('int,long,double' above) for generating the template. 102 103So why does not the TTI library not provide at least this much functionality for 104introspecting member function templates, even if it represents a partially flawed 105way of doing so ? 106 107The reason is stunningly disappointing. Although the above code is perfectly correct C++ 108code ( 'clang' works correctly ), two of the major C++ compilers, in all of their different 109releases, can not handle the above code correctly. Both gcc ( g++ ) and Visual C++ incorrectly 110choose the wrong 'check' function even when the correct 'check' function applies ( Comeau C++ 111also fails but I am less concerned about that compiler since it is not used nearly as much as 112the other two ). All my attempts at alternatives to the above code have also failed. The problems 113with both compilers, in this regard, can be seen more easily with this snippet: 114 115 struct AType 116 { 117 template<class AA> void SomeFuncTemplate() { } 118 }; 119 120 template<class T> 121 struct Test 122 { 123 template<T> struct helper; 124 template<class U> static void check(helper<&U::template SomeFuncTemplate<int> > *) { } 125 }; 126 127 int main() 128 { 129 Test< void (AType::*)() >::check<AType>(0); 130 return 0; 131 } 132 133Both compilers report compile errors with this perfectly correct code, 134 135gcc: 136 137 error: no matching function for call to 'Test<void (AType::*)()>::check(int)' 138 139and msvc: 140 141 error C2770: invalid explicit template argument(s) for 'void Test<T>::check(Test<T>::helper<&U::SomeFuncTemplate<int>> *)' 142 143There is a workaround for these compiler problems, which is to hardcode the name 144of the enclosing class, via a macro, in the generated template rather than pass it as a 145template type. In that case both compilers can handle both the member function code and 146the code snippet above correctly. In essence, when the line: 147 148 template<class U> static void check(helper<&U::template SomeFuncTemplate<int> > *) { } 149 150gets replaced by: 151 152 template<class U> static void check(helper<&AType::template SomeFuncTemplate<int> > *) { } 153 154both gcc and Visual C++ work correctly. The same goes for the 'check' line in the 155'TestFunctionTemplate' above. 156 157But the workaround destroys one of the basic tenets of the TTI library, which is that 158the enclosing class be passed as a template parameter, especially as the enclosing class 159need not actually exist ( see `BOOST_TTI_MEMBER_TYPE` and the previous discussion of 'Nested Types' ), 160without producing a compiler error. So I have decided not to implement even this methodology to 161introspect nested function templates in the TTI library. 162 163[endsect] 164