   [C++] member function detection at compile time
  I came across this code snippet on comp.lang.c++ which detects if a member function with a specific signature exists in a given class or not.  [Sidenote: I know boost has equivalent functionality, but I'm interested in learning how this stuff works, and trying to decrypt the boost headers just doesn't do it for me. :)]If I understand it correctly, the compiler matches the given signature to either one of the two check() functions.  The first being the matching function signature, and the second being a fall-through case for any failed match.  The size of the return value differs for both functions, so the 'value' enum is set appropriately.I noticed this particular code snippet doesn't match const (or volatile, but that can be dealt with later) member functions, however, so I tried changing the code to this:template<class T> struct has_member_Swap; template<class R, class C> class has_member_Swap<R C::*> {private:    template<R C::*> struct helper;    template<R C::* const> struct const_helper;    template<class T> static char check(helper<&T::Swap>*);    template<class T> static char check(const_helper<&T::Swap>*);    template<class T> static char (& check(...))[2];public:    enum { value = sizeof(check<C>(0)) == sizeof(char) }; };struct A { }; struct B {void Swap(B&) const; }; #include <iostream>int main() {std::cout    << has_member_Swap<void (A::*)(A&)>::value << '\n';    << has_member_Swap<void (B::*)(B&)>::value << &std::endl;return 0; }However this still failed to match a const member function.  Any suggestions on what might I have done wrong here?  Thanks in advance![Edit: added sample code, changed title a bit][Edited by - bpoint on April 24, 2009 3:36:21 PM]
  Not that I'm very familiar with these techniques, but this is what I had to do to get it to compile in the first place:template<class C> class has_member_Swap{    private:   template<void (C::*)(C&)> struct helper;   template<void (C::*)(C&) const> struct const_helper;   template<class T> static char check(helper<&T::Swap>*);   template<class T> static char check(const_helper<&T::Swap>*);   template<class T> static char (& check(...))[2];    public:   enum { value = sizeof(check<C>(0)) == sizeof(char) };};class X{public:    void Swap(X&);};class Y{public:    void Swap(Y&) const;};class Z {};#include <iostream>int main(){    std::cout << has_member_Swap<X>::value << '\n';    std::cout << has_member_Swap<Y>::value << '\n';    std::cout << has_member_Swap<Z>::value << '\n';}I don't think a member swap can be a const method, though, if you consider what it does...   ;Quote:Original post by visitorNot that I'm very familiar with these techniques, but this is what I had to do to get it to compile in the first place:*** Source Snippet Removed ***Aaah... hmm.  I don't have any problems compiling on MSVC2005.  What are you using?The difference between your method and the one I'm working with is that you have integrated the actual function signature into your class, whereas mine lets you specify the signature as a template parameter.  I guess I probably should have posted the sample code too.  [Edit: I've updated the original post to include the sample code.]I don't know if it's possible to or not (my template-fu is nearing it's limitations right about now), but I'd like to be able to keep the signature within the template declaration.Quote:Original post by visitorI don't think a member swap can be a const method, though, if you consider what it does...Yeah, this is just a learning exercise.  I was too lazy to change the original code's use of "Swap" to something else.  :)   ;  MingW doesn't compile this at all (I think it doesn't choose the specialization of has_member_Swap at all since it complains about incomplete type right away).I also tried it with Comeau online test version (using static_assert), and it asserts that B does not have the Swap method, and when added C with non-const Swap method, errors out unable to choose between the first two overloads of check.Can't help you more. (I don't think I've ever heard of <R C::*> and I guess <R C::* const> might not mean what one thinks it might mean.)   ;  First of all, thanks for the link to the Comeau online compiler!  (*adds link to bookmarks*)I took your code changes, and simplified it a bit, while still allowing me to specify the desired function signature I wish to detect as a parameter to the template.  This code works on both MSVC2005 and Comeau's compiler:template <typename T, typename U>class has_member_hello_tester{private:template <U> struct helper;template <typename V> static char check(helper<&V::hello> *);template <typename V> static char (&check(...))[2];public:enum { value = (sizeof(check<T>(0)) == sizeof(char)) };};class X{public:void hello();};class Y{public:void hello() const;};class Z {};int main(){static_assert( has_member_hello_tester< X, void (X::*)() >::value == true, "test failed" );static_assert( has_member_hello_tester< X, void (X::*)() const >::value == false, "test failed" );static_assert( has_member_hello_tester< Y, void (Y::*)() >::value == false, "test failed" );static_assert( has_member_hello_tester< Y, void (Y::*)() const >::value == true, "test failed" );static_assert( has_member_hello_tester< Z, void (Z::*)() >::value == false, "test failed" );static_assert( has_member_hello_tester< Z, void (Z::*)() const >::value == false, "test failed" );}Your idea of not using the <R C::*> signature helped me get things fixed.  Thanks for your help!   ;  It also seems OK for gcc.Are you planning to also make it detect any member function (probably possible by turning this into a macro)?   ;  Now you can make code to detect non-member operators and you have all the compile-time detection C++03 can do.   ;Quote:Original post by visitorAre you planning to also make it detect any member function (probably possible by turning this into a macro)?Nope, I'm done here.  I just wanted to learn how it was done.  :)