$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
From: Paul Mensonides (pmenso57_at_[hidden])
Date: 2003-02-05 17:40:36
Peter Dimov wrote:
(Hi, Peter. I'm merging two different posts on this subject and replying to
both simultaneously.)
>>> Yes, exactly. Apologies for the confusion. It is a common mistake to
>>> provide only R T::* and expect that to match all pointers to
>>> members. To get back to your earlier post,
>>>
>>> int (X::*pf) () const;
>>>
>>> is not the same as
>>>
>>> typedef int (*F) () const;
>
> Should be typedef int F() const;
>
>>> since the first typedef is ill-formed, function types cannot be
>>> cv-qualified.
>
> That's 9.3/9, and yes, you are right, the typedef is legal.
Yes an no. The typedef is ill-formed, but not directly because of the
cv-qualification. To be technically accurate here, you cannot form a regular
pointer (or reference) to a cv-qualified function type. It is prohibited. I.e.
typedef int F() const; // legal
typedef int (*F)() const; // illegal
typedef int (&F)() const; // illegal
> I learn
> something new every day. Even though 3.9.3/1 implies that functions
> cannot
> be cv-qualified, and 8.3.5/4 says that creating a cv-qualified
> function type makes the program ill-formed, R T::* still matches a
> const member function, creating a const qualified function type as R.
> Or so Comeau says. C++ sure moves in mysterious ways.
Comeau is correct here. I'll spend a few words to clarify the subject though.
Normal cv-qualification is compounded from some other type, as in "const T." In
the case of function types however, cv-qualification is not compounded. It is
inherently part of the base function type or it isn't. So, from a certain
point-of-view, the above is accurate. You cannot take a function type and
cv-qualify it. However, the function type itself might already be cv-qualified.
In other words, cv-qualification on functions is not normal cv-qualification.
Specifically, it refers to the cv-qualification of the implicit this pointer.
E.g. something like this pseudo code:
typedef void f() const;
...roughly equivalent (in pseudocode) to this:
typedef void f(const class* this);
...which is why certain limitations exist on cv-qualified function types.
Specifically, they can only be used in three ways: 1) to declare a non-static
member function 2) to declare the pointed-to type of a pointer-to-member, and 3)
to declare another typedef. Note that in the first two cases (i.e. the cases of
actual use), the pseudo-type 'class' in the above can be deduced, either from
the enclosing class or from the pointer-to-member class type. Any other use is
illegal--such as forming a regular pointer or reference to a cv-qualified
function type. Then second case is interesting in the particular case of
detecting pointers-to-member-functions. The following is all legal:
typedef void F() const;
struct X {
F f;
};
void X::f() const { }
F X::* pf = &X::f;
By the same token, the function type 'F' can be extracted from a
pointer-to-member-function with the specialization "R X::*" with 'R' being the
original function type:
#include <iostream>
template<class, class> struct is_same {
enum { value = false };
};
template<class T> struct is_same<T, T> {
enum { value = true };
};
template<class> struct extract;
template<class R, class C> struct extract<R C::*> {
enum { value = is_same<R, F>::value };
};
int main() {
std::cout
<< extract<F X::*>::value // 1
<< &std::endl;
return 0;
}
Just for the record, however, Comeau doesn't get this whole area right (and many
other compilers don't get it right at all). Comeau doesn't consider the type
extracted from a pointer-to-member-function to be a regular function type.
Rather, it considers it to be some type of psuedo-function-type ala "member
function type"--which is incorrect. An example demonstrates this:
#include <iostream>
#include <typeinfo>
typedef void F();
struct X { };
typedef F X::* PMF;
template<class> struct extract;
template<class R, class C> struct extract<R C::*> {
typedef R type;
};
extract<PMF>::type f; // decl: no error
void f() { return; } // def: error
int main() {
std::cout
<< typeid(f).name() // compiler crash
// i.e. not an ICE
<< &std::endl;
return 0;
}
I've been talking about this issue with Daveed Vandevoorde for the last couple
weeks, so EDG is aware of the issue.
Paul Mensonides