Boost logo

Boost :

From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2007-04-02 19:56:07


I've attached a rewrite of the patch I previously submitted that
includes documentation and new tests in MPL's test suite. Apply with
'patch -p0 < djw_has_xxx_template.patch' from the boost root

This implementation is based on comp.lang.c++.moderated USENET
postings from Rani Sharoni (2002-03-17, and
Aleksey Gurtovoy (2002-03-19,, the current
has_xxx implementation (especially ideas in the msvc 8.0
implementation from Daniel Wallin, I believe), the 3rd code example in
section 14.2.8 of the standard, and the discussion on this thread
(especially postings from Guillaume Melquiond who pointed out to me
the need for a seperate "substitute" template). Also, thanks to
Aleksey Gurtovoy and David Abrahams for implementing has_xxx in the
first place and especially for including citations of the USENET
discussions in has_xxx.hpp. They were invaluable.

By testing combinations of different members, member names, member
types, and member template arities, I have 142 individual tests (i.e.
assertions) for detecting member templates. Here is the pass/fail rate
for the compilers I tested.

gcc 3.4, 4.0, 4.1 - 142/142
gcc 3.3 - 139/142
msvc 7.1, 8.0: 142/142
comeau 4.3.8 alpha online: 93/142 (I had to run it through the
preprocessor and then paste it on the website's form)

The tests that fail on gcc 3.3 are for rejecting member templates with
the correct name but incorrect number of parameters. Comeau also
cannot do this and additionally cannot reject members with the correct
name that aren't templates (typedefs and structs) and cannot detect
member templates with the correct name but no required parameters (all
parameters have defaults).

Other changes from my previous patch include:

1) changed the name of BOOST_MPL_HAS_TEMPLATE_XXX_TRAIT_DEF to
BOOST_MPL_HAS_XXX_TEMPLATE_DEF, same for NAMED_DEF version. It's more
concise. Also, by default the name of the generated metafunction is a
concatination of 'has_' and the name of the nested template rather
than 'has_template_' and the name of the nested template. This is also
done for brievity's sake.

2) included the macro definitions in has_xxx.hpp rather than creating
new files. These are closely related, and at some point in the future
the implementations for has_xxx for nested types and has_xxx for
nested templates could be folded together to improve code reuse.

3) created the following new documentation files
- libs/mpl/doc/src/refmanual/CFG_NO_HAS_TEMPLATE_XXX.rst
- libs/mpl/doc/src/refmanual/HAS_XXX_TEMPLATE_DEF.rst
- libs/mpl/doc/src/refmanual/HAS_XXX_TEMPLATE_NAMED_DEF.rst
I wasn't sure how to generate the HTML and pdf manuals.

4) added the tests to has_xxx.cpp and no_has_xxx.cpp

I'm assuming this is too late to be considered for 1.34, so I built
the patch off the cvs trunk rather than RC_1_34_0. I replaced my
previous patch on SF patch tracker with the current one.

As for future work:
1) Though the two most common compilers, gcc 4 and msvc 7.1/8.0, pass
all the tests, it would be nice to have work arounds so that all
compilers pass all the tests.

2) I believe this can be extended along the lines of John Madsen's
comp.lang.c++.moderated posting (1999-11-12, to test for other sorts of members by
creating new substitute templates for SFINAE. I made an initial try at
detecting member data and had some success. If there's interest I
could look into extending has_xxx for member templates into a more
complete set of compile time type introspection metafunctions...
something like has_member_data, has_member_function, has_member_type,
has_member_template. The last two metafunction would supersede the
currect has_xxx and my has_xxx for templates.

Let me know if you have trouble applying the patch or if you have
suggests to improve this.


The example of using BOOST_MPL_HAS_XXX_TEMPLATE_DEF that I posted with
my original patch should now look like the following (if you want to
copy and past it for a quick test).

#include <utility>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/has_xxx.hpp>
#include <boost/utility/result_of.hpp>

// Create has_result to detect nested members like
// template<class T> struct result {}.
// The first macro argument is the member name and the second argument
// is the number of template parameters.

struct pair_maker {
   template<typename F> struct result;
   template<typename F, typename Arg0, typename Arg1>
   struct result<F(Arg0, Arg1)> {
       typedef std::pair<Arg0, Arg1> type;

   template<typename Arg0, typename Arg1>
   typename result<pair_maker(Arg0, Arg1)>::type
   operator()(Arg0 a0, Arg1 a1) const
       return std::make_pair(a0, a1);

int main()
   using namespace boost;

   typedef char value_type;
           pair_maker(value_type, value_type)

   typedef result_of<
       pair_maker(value_type, value_type)
>::type result_type;

   value_type x, y;
   pair_maker f;
   result_type result = f(x, y);

Boost list run by bdawes at, gregod at, cpdaniel at, john at