lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re[2]: [lmi] Difficulty writing a generic contains() function template


From: Vadim Zeitlin
Subject: Re[2]: [lmi] Difficulty writing a generic contains() function template
Date: Wed, 12 May 2010 00:33:38 +0200

On Tue, 11 May 2010 19:09:19 +0000 Greg Chicares <address@hidden> wrote:

GC> On 2010-05-05 13:37Z, Vadim Zeitlin wrote:
GC> [...]
GC> >  Whether it's really better than just defining a traits type and
GC> > specializing it for all the container types is open to discussion. Notice
GC> > that it took me more than half an hour to get this right...
GC> 
GC> That's much less time than it would have taken me

 Notice that I didn't start from scratch, I had a vague recollection of
this technique from reading comp.lang.c++.moderated before and a quick
Google search confirmed that the usual way to test for a method existence
(without checking its exact signature, things are completely different if
you do want to test this) was to exploit an ambiguity like the one below.
This is a quite non-obvious hack, I'm pretty sure I wouldn't have found it
in half an hour if I hadn't already known about it.


GC> > template <class T>
GC> > struct has_find_method {
GC> >     struct BaseFind { void find(); };
GC> >     struct Base : T, BaseFind {};
GC> > 
GC> >     template <typename FP, FP fp> struct Tester;
GC> > 
GC> >     template <class U>
GC> >     static char test(U *, Tester<void (BaseFind::*)(), &U::find>* = 0);
GC> >     static long test(...);
GC> > 
GC> >     static const bool value = sizeof(test(static_cast<Base *>(0))) != 1;
GC> > };
GC> 
GC> As far as I understand it, SFINAE comes into play here because the
GC> template form of test() is ambiguous when T has a find() member.

 Yes, exactly. I probably should have included a comment making this
explicit, but the idea is that the expression &Base::find can be converted
to the type "void (BaseFind::*)()" only if the class T does not have
another find() method, otherwise there is an ambiguity. It's just what you
said above, of course, just in other words.

GC> What I don't understand is why ambiguity causes substitution failure,
GC> at least under ISO/IEC 14882 2003-10-15 [14.8.2/2]. I don't see which
GC> of the "--Attempting to..." subparagraphs would address ambiguity.
GC> Am I missing something?
GC> 
GC> OTOH, N3092 of 2010-03-26 [14.8.2.8] says deduction fails
GC>   "if a substitution results in an invalid type or expression"
GC> and the small testcase above certainly does seem to involve an invalid
GC> expression. So does this technique actually depend on changes to the
GC> language standard that have not yet formally been adopted? I'm trying
GC> to understand how "exotic" this is.

 I didn't even think to find the basis for this technique in the Standard
for two reasons: first, there are so many things in it that the compilers
don't (or badly) implement that it's usually much more important to know
whether something works in practice than whether it's supposed to work in
theory. But second it was obvious to me that a template substitution can't
succeed when it involves an invalid type conversion. Because this is really
what happens here: U::find() is not of type FP when T::find() exists. So I
think that the paragraph which applies is the third from end of 14.8.2/2:

        - Attempting to perform an invalid conversion in either a template
          argument expression, or an expression used in the function
          declaration.

They even give an example similar to what is done here:

        template <class T,T*> int f(int);
        int i2 = f<int,1>(0);   // can't convert 1 to int*

And here we "can't convert &U::find to void (BaseFind::*)()". Of course,
"&U::find" is not only not convertible to this type but is even invalid but
I don't think this can make the substitution valid, can it?


 To summarize, I think this should work according to C++98 and am really
surprised that Comeau didn't compile it (sorry for not checking it myself
BTW). But I'm not a [language] lawyer so maybe I'm missing something.

 Regards,
VZ

reply via email to

[Prev in Thread] Current Thread [Next in Thread]