starting to learn Boost MPL and type_trait
Hello all, I am trying to start learning the Boost MPL. The internals are more interesting for me then the usage I read both Abrahams&Gurtovoy and Alexandrescu books (both excelent btw) Some things i still don't quite understand: 1. How (or rather Why) does is_class works. 2. Same for is_enum 3. Can someone explain how MPL lambda works specially how the "_" works I tried to scan some of the archives but could not find any definite answer - i guess the discussions if they were are lost. P.S. neat trick to someone who try to learn the internals is to make a program that just include the header u interested to learn and just do the "pre-compile" stage (/EP /P flags in VC7.1 iirc) - you get a nice header without the unreadable MACROS. Thanks
1. How (or rather Why) does is_class works.
There are two key concepts: 1) A class type is the only kind of type that can have a member function. 2) When the compiler performs template argument substition to a function signature, if the signature is an invalid type then the signature is ignored without a compiler error (sometimes called Substitution Failure Is Not An Error or SFINAE). So given the overloads: template <class T> void f(int (T::*)(int)); / #1 template <class T> void f(...); // #2 The expression: f<T>(0); Will call #1 if T is a class type, or #2 otherwise.
2. Same for is_enum
An enum type is the only type that has a built-in implicit conversion to int, but is not itself an integer type. Combine that with the fact that only one user-defined conversion may be performed per conversion sequence, and you have the implementation. John.
John Maddock wrote:
1. How (or rather Why) does is_class works.
There are two key concepts:
1) A class type is the only kind of type that can have a member function. 2) When the compiler performs template argument substition to a function signature, if the signature is an invalid type then the signature is ignored without a compiler error (sometimes called Substitution Failure Is Not An Error or SFINAE).
So given the overloads:
template <class T> void f(int (T::*)(int)); / #1 template <class T> void f(...); // #2
The expression:
f<T>(0);
Will call #1 if T is a class type, or #2 otherwise.
2. Same for is_enum
An enum type is the only type that has a built-in implicit conversion to int, but is not itself an integer type. Combine that with the fact that only one user-defined conversion may be performed per conversion sequence, and you have the implementation.
John.
Thanks for the reply. The thing i dont understand is this : template <class T> void f(int (T::*)(int)) will match any member function with specific signature (receiving int and returning int). But not all classes have such function. So in this case how will a class F { } be matched ? The only function that always exist for all classes with the same signature is a destructor ( with void (void) signature ?) - is this the function that is used ? Thanks Sharon
Sharon Galtzur wrote:
Thanks for the reply. The thing i dont understand is this : template <class T> void f(int (T::*)(int)) will match any member function with specific signature (receiving int and returning int). But not all classes have such function. So in this case how will a class F { } be matched ?
No member of the given type need exist for the pointer-to-member type to be well-formed. Consider: struct C { }; typedef void (C::*mem_fun) (std::string); The later expression defines a type which can have no instances, but this doesn't prevent it from being used in a function declaration: void f(mem_fun mf); Jonathan
Jonathan Turkanis wrote:
Sharon Galtzur wrote:
Thanks for the reply. The thing i dont understand is this : template <class T> void f(int (T::*)(int)) will match any member function with specific signature (receiving int and returning int). But not all classes have such function. So in this case how will a class F { } be matched ?
No member of the given type need exist for the pointer-to-member type to be well-formed. Consider:
struct C { };
typedef void (C::*mem_fun) (std::string);
The later expression defines a type which can have no instances, <snip>
Actually it can:
struct D : C { void foo(std::string); };
mem_fun mf = static_cast
Ben Hutchings
Actually it can:
struct D : C { void foo(std::string); };
mem_fun mf = static_cast
(&D::foo); Not that I'd recommend doing that, as it invites type errors.
Creating an instance by breaking the type system is cheating. Why not
reinterpret_cast
David Abrahams wrote:
Ben Hutchings
writes: Actually it can:
struct D : C { void foo(std::string); };
mem_fun mf = static_cast
(&D::foo); Not that I'd recommend doing that, as it invites type errors.
Creating an instance by breaking the type system is cheating. Why not reinterpret_cast
("foo"), for that matter? A simpler instance of the type is:
mem_fun mf = 0;
Okay, okay, I was all wrong ;)
Cheers,
Jonathan
David Abrahams wrote:
Ben Hutchings
writes: Actually it can:
struct D : C { void foo(std::string); };
mem_fun mf = static_cast
(&D::foo); Not that I'd recommend doing that, as it invites type errors.
Creating an instance by breaking the type system is cheating.
That doesn't break the type system. The result is well-defined; see 5.2.9/9 in the standard.
Why not reinterpret_cast
("foo"), for that matter?
That's ill-formed.
A simpler instance of the type is:
mem_fun mf = 0;
Yes, and as you know that's what the type trait relies on. Ben.
Ben Hutchings
David Abrahams wrote:
Ben Hutchings
writes: Actually it can:
struct D : C { void foo(std::string); };
mem_fun mf = static_cast
(&D::foo); Not that I'd recommend doing that, as it invites type errors. Creating an instance by breaking the type system is cheating.
That doesn't break the type system. The result is well-defined; see 5.2.9/9 in the standard.
If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the result of the cast is undefined. [Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member; see expr.mptr.oper. ] That part in brackets contradicts you in this case. But then, it's non-normativve and the section it references seems to actually only apply when the pointer is dereferenced. I'm slightly confused.
Why not reinterpret_cast
("foo"), for that matter? That's ill-formed.
Where is that in the standard? I see no restrictions on the use of reinterpret_cast.
A simpler instance of the type is: mem_fun mf = 0;
Yes, and as you know that's what the type trait relies on.
No, I didn't. -- Dave Abrahams Boost Consulting www.boost-consulting.com
Ben Hutchings wrote:
Jonathan Turkanis wrote:
Sharon Galtzur wrote:
Thanks for the reply. The thing i dont understand is this : template <class T> void f(int (T::*)(int)) will match any member function with specific signature (receiving int and returning int). But not all classes have such function. So in this case how will a class F { } be matched ?
No member of the given type need exist for the pointer-to-member type to be well-formed. Consider:
struct C { };
typedef void (C::*mem_fun) (std::string);
The later expression defines a type which can have no instances, <snip>
Actually it can:
struct D : C { void foo(std::string); };
mem_fun mf = static_cast
(&D::foo); Not that I'd recommend doing that, as it invites type errors.
Oops! I should have made C sealed ;-)
Ben.
Jonathan
Sharon Galtzur
3. Can someone explain how MPL lambda works specially how the "_" works
That's a long-ish story. If by any chance you can attend the SD West conference in March, I'll be covering that as part of my "Inside the Boost Libraries" talk: http://www.cmpevents.com/SDw5/a.asp?option=C&V=11&SessID=4146&Mgt=0&RVid=0 -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams wrote:
Sharon Galtzur
writes: 3. Can someone explain how MPL lambda works specially how the "_" works
That's a long-ish story. If by any chance you can attend the SD West conference in March, I'll be covering that as part of my "Inside the Boost Libraries" talk:
http://www.cmpevents.com/SDw5/a.asp?option=C&V=11&SessID=4146&Mgt=0&RVid=0
Thanks for the reply - sadly i am in the wrong continent and wont be able to paticipate in this. Will there be summery available of this conference ? Thanks, Sharon
Sharon Galtzur
David Abrahams wrote:
Sharon Galtzur
writes: 3. Can someone explain how MPL lambda works specially how the "_" works That's a long-ish story. If by any chance you can attend the SD West conference in March, I'll be covering that as part of my "Inside the Boost Libraries" talk: http://www.cmpevents.com/SDw5/a.asp?option=C&V=11&SessID=4146&Mgt=0&RVid=0
Thanks for the reply - sadly i am in the wrong continent and wont be able to paticipate in this. Will there be summery available of this conference ?
That's up to the conference organizers, but I'd guess not: it's a huge event. -- Dave Abrahams Boost Consulting www.boost-consulting.com
participants (5)
-
Ben Hutchings
-
David Abrahams
-
John Maddock
-
Jonathan Turkanis
-
Sharon Galtzur