Topic: has_mem_func<T>::value? (Is this legal?)


Author: rani_sharoni@hotmail.com (Rani Sharoni)
Date: Wed, 8 May 2002 16:08:14 GMT
Raw View
"Anthony Williams"<anthwil@nortelnetworks.com> wrote in message news:<aa8c1a$bsj$1@bcarh8ab.ca.nortel.com>...
> "Paul Mensonides" <pmenso57@attbi.com> wrote in message
> news:8Box8.117046$CH1.103235@sccrnsc02...
> > "Anthony Williams" <anthwil@nortelnetworks.com> wrote in message
> > news:aa3hj3$7nu$1@bcarh8ab.ca.nortel.com...
> > 14.8.2p2 third bullet, third sub-bullet seems to say it is legal.

> It is the "...that names a type..." part that makes me dubious --- with the
> lack of a typename prefix, T::self doesn't name a type:

Sorry for the late response.

I think that Comeau made that decision based on some wide
interpretation of the following reason (number 7) for type deduction
failure in 14.8.2/2:
Attempting to perform an invalid conversion in either a template
argument expression, or an expression used in the function
declaration.

To check my claim I compiled the following code:

<code>
struct C { struct B; };

template<template<typename> class>
struct Template2Type;

template<typename T>
char* f1(Template2Type<T::template B> *);

template<typename>
int*  f1(...);

int *i1 = f1<C>(0);
</code>

This code compiled fine (using Comeau C/C++ 4.3 BETA#3) because the
deduction of the first f1 failed leaving the f1(   ) as the only
candidate (14.8.3/1).

Later I checked the following "similar" code:

<code>
struct C { struct B; };

template<typename T>
char* f2(typename T::template B<int> *);

template<typename>
int*  f2(...);

int *i2 = f2<C>(0);
// error: name following "template" must be a member template
// char* f2(typename T::template B<int> *);
//detected during instantiation of "f2" based on template argument<C>
// error: a value of type "char *" cannot be used to initialize an
// entity of type "int *"
</code>

The above code and the compilation failure indicate that the compiler
deduction for the first f2 success and this function selected to be
instantiate. Later the instantiation failed for obvious reason.

I didn't find any explicit listed reason for the above code behavior
and neither to the has_mem_func behavior except for assuming that they
are both an illegal conversion.
It seems that according to Comeau if there is empty set of candidates
to convert then the conversion fails.

I did notice that the word expression is mentioned in the quoted
sentence and perhaps "T::template B" is a template argument
expression.

In order to have another support to my assumption I believed that the
following code should compile by Comeau:

<code>
template<typename> struct Type2Type;

struct C  {  template<typename> struct B;  };

template<typename T>
char* f3(Type2Type<typename T::B> *);

template<typename>
int*  f3(...);

int* i2 = f3<C>(0);
// internal error: assertion failed at: "templates.c", line 6285

</code>

Has you can see the ICE left this issue vague.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Anthony Williams"<anthwil@nortelnetworks.com>
Date: Thu, 25 Apr 2002 17:38:51 GMT
Raw View
"Paul Mensonides" <pmenso57@attbi.com> wrote in message
news:8Box8.117046$CH1.103235@sccrnsc02...
> "Anthony Williams" <anthwil@nortelnetworks.com> wrote in message
> news:aa3hj3$7nu$1@bcarh8ab.ca.nortel.com...
>
> > Type deduction cannot succeed, as &X::self is an invalid expression. It
> > could be argued (1) that the program is ill-formed, as this expression
is
> > ill-formed. Alternatively, it could be argued (2) that
> > helper<X>::inner<&X::self> is therefore an "invalid type", so type
deduction
> > fails by the main text of 14.8.2p2, third bullet.
> >
> > I would go for option (2) --- type deduction fails, and overload
resolution
> > continues. The version of check with ellipsis is now the only candidate,
and
> > is therefore chosen as the best match. This is the desired behaviour.
>
> 14.8.2p2 third bullet, third sub-bullet seems to say it is legal.
>
> "Attempting to use a type in the qualifier portion of a qualified name
that
> names a type when that type does not contain the specified member, or if
the
> specified member is not a type where a type is required."


It is the "...that names a type..." part that makes me dubious --- with the
lack of a typename prefix, T::self doesn't name a type:

>> Had the
>> qualified name X::self been prefixed by "typename" to designate a type,
then
>> type deduction would have been explicitly allowed to fail by the third
>> sub-bullet of the third bullet of 14.8.2p2. However, X::self designates a
>> data member or member function, as it is not prefixed by "typename", so
this
>> doesn't apply.

Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optical Components Ltd
The opinions expressed in this message are not necessarily those of my
employer


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Paul Mensonides" <pmenso57@attbi.com>
Date: Tue, 23 Apr 2002 08:26:57 GMT
Raw View
Hello, I'm curious about the legality of the following construct.  It is
attempting to test where a give type has a given member function named 'self'.

typedef char small_t;
typedef char (& large_t)[256];

template<class T> struct has_self {
    private:
        template<class U>
        struct helper {
            template<void (U::*)(void)>
            struct inner { };
        };
        template<class U>
        static small_t check(
            typename helper<U>::template inner<&U::self>* );
        template<class U>
        static large_t check(...);
    public:
        enum { value = sizeof(check<T>(0)) == sizeof(small_t) };
};

struct X { };

struct Y {
    void self(void) {
        return;
    }
};

int main() {
    std::cout << has_self<X>::value << '\n'
        << has_self<Y>::value << &std::endl;
    return 0;
}

This compiles and works as desired on Comeau C++.  I'm am just wondering if it
is *legal* C++.

Paul Mensonides

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Anthony Williams"<anthwil@nortelnetworks.com>
Date: Wed, 24 Apr 2002 00:45:36 GMT
Raw View
"Paul Mensonides" <pmenso57@attbi.com> wrote in message
news:Ox3x8.2363$vX.2728@rwcrnsc53...
> Hello, I'm curious about the legality of the following construct.  It is
> attempting to test where a give type has a given member function named
'self'.
>
> typedef char small_t;
> typedef char (& large_t)[256];
>
> template<class T> struct has_self {
>     private:
>         template<class U>
>         struct helper {
>             template<void (U::*)(void)>
>             struct inner { };
>         };
>         template<class U>
>         static small_t check(
>             typename helper<U>::template inner<&U::self>* );
>         template<class U>
>         static large_t check(...);
>     public:
>         enum { value = sizeof(check<T>(0)) == sizeof(small_t) };
> };

> struct X { };
>
> struct Y {
>     void self(void) {
>         return;
>     }
> };
>

Taking things piecemeal, the helper struct is valid, as are the two
overloads of check. The crunch question is, of course, what happens in
defining the enum value.

check<T> could refer to either of the function templates, so we have to
undergo Overload Resolution (14.8.3). Therefore (by 14.8.3p1) we have to do
Template Argument Deduction (14.8.2) for each template.

The key paragraph is (as usual) 14.8.2p2, in particular the third bullet
"... If a substitution in a template parameter or in the function type of
the function template results in an invalid type, type deduction fails...."

check(...) always works, the question is the other one

If T==Y, then U==Y, so we try check(helper<Y>::inner<&Y::self>*), which is
OK, as Y::self has the correct signature. This version of check is therefore
chosen as the best match, since any match is better than ellipsis.

If T==X, then U==X, so we try check(helper<X>::inner<&X::self>*). This is
problematic. X::self is ill-formed, as X has no member self. Had the
qualified name X::self been prefixed by "typename" to designate a type, then
type deduction would have been explicitly allowed to fail by the third
sub-bullet of the third bullet of 14.8.2p2. However, X::self designates a
data member or member function, as it is not prefixed by "typename", so this
doesn't apply.

There are three possible outcomes:

* Type deduction succeeds
* Type deduction fails
* The program is ill-formed

Type deduction cannot succeed, as &X::self is an invalid expression. It
could be argued (1) that the program is ill-formed, as this expression is
ill-formed. Alternatively, it could be argued (2) that
helper<X>::inner<&X::self> is therefore an "invalid type", so type deduction
fails by the main text of 14.8.2p2, third bullet.

I would go for option (2) --- type deduction fails, and overload resolution
continues. The version of check with ellipsis is now the only candidate, and
is therefore chosen as the best match. This is the desired behaviour.

> int main() {
>     std::cout << has_self<X>::value << '\n'
>         << has_self<Y>::value << &std::endl;
>     return 0;
> }
>
> This compiles and works as desired on Comeau C++.  I'm am just wondering
if it
> is *legal* C++.

I believe so.

Anthony
--
Anthony Williams
Software Engineer, Nortel Networks Optical Components Ltd
The opinions expressed in this message are not necessarily those of my
employer


---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Paul Mensonides" <pmenso57@attbi.com>
Date: Wed, 24 Apr 2002 15:30:53 GMT
Raw View
"Anthony Williams" <anthwil@nortelnetworks.com> wrote in message
news:aa3hj3$7nu$1@bcarh8ab.ca.nortel.com...

> Type deduction cannot succeed, as &X::self is an invalid expression. It
> could be argued (1) that the program is ill-formed, as this expression is
> ill-formed. Alternatively, it could be argued (2) that
> helper<X>::inner<&X::self> is therefore an "invalid type", so type deduction
> fails by the main text of 14.8.2p2, third bullet.
>
> I would go for option (2) --- type deduction fails, and overload resolution
> continues. The version of check with ellipsis is now the only candidate, and
> is therefore chosen as the best match. This is the desired behaviour.

14.8.2p2 third bullet, third sub-bullet seems to say it is legal.

"Attempting to use a type in the qualifier portion of a qualified name that
names a type when that type does not contain the specified member, or if the
specified member is not a type where a type is required."

Paul Mensonides

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]