Member function detection: VC7.1 workaround needed

Hi All, I'm writing a macro-based interface definition language, which I hope to post soon. For this, I need to be able to detect the presence of member functions with given name and signature. My current formulation generates code like the following to test whether a class has a non-const member function named 'one' with the signature char(int, float): template<typename T> struct has_member_function_one { template<typename U, char (U::*MemFun)(int, float)> struct one_holder { }; static ::boost::type_traits::no_type one_tester(...); template<typename U> static ::boost::type_traits::yes_type one_tester ( ::boost::mpl::identity<U>*, one_holder<U, &U::one>* = 0 ); static const bool value = sizeof(one_tester((::boost::mpl::identity<T>*)0)) == sizeof(::boost::type_traits::yes_type); typedef ::boost::mpl::bool_<value> type; }; This works fine on Comeau 4.3.3, Intel 8.0 for Windows, GCC 3.4.1 and VC8.0 (beta). But on VC7.1, it works only if the member function 'one' is not overloaded. I've tried Terje Slettebø's operator_concept_traits library, some code posted long ago by Brock Peabody, but they all use the same technique and fail on VC7.1. Does anyone have a workaround? Best Regards, Jonathan

Jonathan Turkanis wrote:
Hi All,
I'm writing a macro-based interface definition language, which I hope to post soon. For this, I need to be able to detect the presence of member functions with given name and signature. My current formulation generates code like the following to test whether a class has a non-const member function named 'one' with the signature char(int, float):
Attached code works in MSVC71. Maybe this will give you some idea.
cl /GX /GR T543.cpp
/out:T543.exe T543.obj
T543 1 0 0 0 0 1
B. #include <iostream> template <typename Type> class has_member__one { // 1. SIGNATURE goes here template <char (Type::*)(int, float)> struct helper{}; typedef char (&yes) [1]; typedef char (&no) [2]; template <typename Type_> // 2. NAME goes here static yes test (helper<&Type_::one>*); template <typename Type_> static no test (...); public: enum {value = sizeof(test<Type>(0)) == sizeof(yes)}; }; struct A // 1 { char one(int, float); }; struct B // 0 { int one; }; class C // 0 { }; struct D // 0 { float one(); void one(int, float); void one(int, int); }; struct E // 0 { int one(int); int one(int, int); char one(int, float) const; }; struct F // 1 { void one(int); char one(int, int); char one(int, float); char one(int, float) const; }; int main() { std::cout << has_member__one<A>::value << std::endl; std::cout << has_member__one<B>::value << std::endl; std::cout << has_member__one<C>::value << std::endl; std::cout << has_member__one<D>::value << std::endl; std::cout << has_member__one<E>::value << std::endl; std::cout << has_member__one<F>::value << std::endl; }

"Bronek Kozicki" <brok@rubikon.pl> wrote in message news:4195FD3C.4010801@rubikon.pl...
Jonathan Turkanis wrote:
Hi All,
I'm writing a macro-based interface definition language, which I hope to post soon. For this, I need to be able to detect the presence of member functions with given name and signature. My current formulation generates code like the following to test whether a class has a non-const member function named 'one' with the signature char(int, float):
Attached code works in MSVC71. Maybe this will give you some idea.
Thanks! I'll try it later today. Perhaps Terje Slettebo would also be interested in this. Jonathan

"Bronek Kozicki" <brok@rubikon.pl> wrote in message news:4195FD3C.4010801@rubikon.pl...
Jonathan Turkanis wrote:
Hi All,
I'm writing a macro-based interface definition language, which I hope to post soon. For this, I need to be able to detect the presence of member functions with given name and signature. My current formulation generates code like the following to test whether a class has a non-const member function named 'one' with the signature char(int, float):
<snip>
template <typename Type> class has_member__one { // 1. SIGNATURE goes here template <char (Type::*)(int, float)> struct helper{};
typedef char (&yes) [1]; typedef char (&no) [2];
template <typename Type_> // 2. NAME goes here static yes test (helper<&Type_::one>*);
template <typename Type_> static no test (...);
public: enum {value = sizeof(test<Type>(0)) == sizeof(yes)}; };
Hi Bronek, Thanks for your effort coming up with this workaround. Unfortunately, although it works okay (when modified as described below) in isolation, when it is generated by macros as a deeply nested template, something goes wrong and it doesn't handle overloading. I'd like to point out two things about the above implementation, for anyone who might be following this thread. 1. I believe it is non-conforming, since explicitly specifying the template argument Type should suppress template argument deduction and therefore SFINAE. But this is irrelevant for a broken-compiler workaround. 2. It's necessary to verify that the main template parameter Type is a class type before using the expression char (Type::*)(int, float) as a template parameter. But this is easy using is_class. Thanks again, Jonathan

"Jonathan Turkanis" <technews@kangaroologic.com> writes:
1. I believe it is non-conforming, since explicitly specifying the template argument Type should suppress template argument deduction and therefore SFINAE.
I don't think that's the case. Recall that SFINAE also works on partial class template specializations. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

"David Abrahams" <dave@boost-consulting.com> wrote in message news:upt2ekmf9.fsf@boost-consulting.com...
"Jonathan Turkanis" <technews@kangaroologic.com> writes:
1. I believe it is non-conforming, since explicitly specifying the template argument Type should suppress template argument deduction and therefore SFINAE.
I don't think that's the case. Recall that SFINAE also works on partial class template specializations.
I think you're right. I should have reread 14.8.2 before making this claim. Jonathan

Jonathan Turkanis wrote:
Thanks for your effort coming up with this workaround. Unfortunately, although it works okay (when modified as described below) in isolation, when it is generated by macros as a deeply nested template, something goes wrong and it doesn't handle overloading.
Coud you pls. send me code to reproduce problem? I will try to find a fix.
1. I believe it is non-conforming, since explicitly specifying the template argument Type should suppress template argument deduction and therefore SFINAE. But this is irrelevant for a broken-compiler workaround.
I'm pretty sure that you are wrong. There are *two* template functions taking single type parameter, thus explicit specification of template arguments just "limits" overload set to these two templates. But still, there is some overload set. Selection is performed by partial ordering of template functions, as type of only parameter of one of them is valid only for type satisfying our requirements. Just to confirm this, see results of the same program on Comeau 4.3.3 and GCC 3.4.2:
como --a T543.cpp -oT543 Comeau C/C++ 4.3.3 (Jan 13 2004 11:29:09) for MS_WINDOWS_x86 Copyright 1988-2003 Comeau Computing. All rights reserved. MODE:strict warnings C++
T543 1 0 0 0 0 1
g++ -W -Wall --pedantic-errors --ansi T543.cpp -oT543
T543 1 0 0 0 0 1
2. It's necessary to verify that the main template parameter Type is a class type before using the expression char (Type::*)(int, float) as a template parameter. But this is easy using is_class.
Right. Otherwise hard to understand compilation error may happen. B.

"Bronek Kozicki" <brok@rubikon.pl> wrote in message news:4199F881.2040005@rubikon.pl...
Jonathan Turkanis wrote:
Thanks for your effort coming up with this workaround. Unfortunately, although it works okay (when modified as described below) in isolation, when it is generated by macros as a deeply nested template, something goes wrong and it doesn't handle overloading.
Coud you pls. send me code to reproduce problem? I will try to find a fix.
Thanks for the offer. I will try to do this, but it a non-trivial task, some of the code is output of the preprocessor, and some hand written. There are a lot of mangled names and a lot of irrelevant stuff.
1. I believe it is non-conforming, since explicitly specifying the template argument Type should suppress template argument deduction and therefore SFINAE. But this is irrelevant for a broken-compiler workaround.
I'm pretty sure that you are wrong. There are *two* template functions
Yes, I'm now convinced I was wrong. Template arguments must still be compatible even if they are explicitly specified, and 14.8.2/2 governs this. Jonathan
participants (3)
-
Bronek Kozicki
-
David Abrahams
-
Jonathan Turkanis