|
Boost : |
From: Aleksey Gurtovoy (agurtovoy_at_[hidden])
Date: 2002-10-09 02:57:53
David B. Held wrote:
> > Fixing a missing typename
>
> Technically, my version wasn't missing a typename, because I was using
> is_same<>::value with if_c. ;)
And I wasn't referring to that one :).
typedef typename mpl::if_c<
::boost::is_same<i_, mpl::end<Sequence>::type >::value,
^^^^^^^^^^^^^^^^^^^^^^^^
make_iterator<Default>, i_
>::type::type type;
>
> > and style a little bit, here's an "approved" version :)
>
> But I do like your version better. Thanks for the tip. I
> see that apply_if combines an if_ with a dereference, which happens
> to be the same as an apply. I wouldn't have figured that out on my own.
;)
http://www.mywikinet.com/mpl/#applyif, the last paragraph:
"The described technique is so common in template metaprograms, that it
makes sense to facilitate the selection of the nested type member by
introducing a high level equivalent to if_ that will do func_::type
operation as a part of its invocation. The MPL provides such a template -
it's called apply_if. ..."
> Now, I notice that you don't bother to hide "private metavariables",
> but just make everything struct. Is that simply because it would be silly
to
> try to use any of the the intermediate results, and thus there's no point
to
> try to hide any of the implementation details?
In the library code, I usually do hide auxiliary typedefs declared directly
in the scope of a public component:
template< typename T > struct my_algorithm
{
private:
typedef /* ... */ iter_;
typedef /* ... */ last_;
public:
typedef /* ... */ type;
};
to denote even more explicitly that members with '_' suffix do not comprise
a public interface. I usually don't bother with it in the scope of
implementation structs:
namespace aux {
template< typename T > struct my_impl
{
typedef /* ... */ iter_;
typedef /* ... */ last_;
typedef /* ... */ type;
};
}
// often defined in a separate header
template< typename T > struct my_algorithm
: aux::my_impl<T>
{
};
mostly because I am lazy ;).
>
> > [...]
> > A question - why BOOST_STORAGE_POLICY et al. instead of, let's say,
> >
> > typename get_storage_policy<policies_,T>::type
> >
> > ?
>
> Good question. Two reasons. One, repetition. They appear twice, and
> something as complex as this isn't something I want to spend time on
> synchronizing whenever I make a minor change (this is the
> kind of thing I'd spend an hour on diagnosing).
But from maintenance point of view the difference between
# define BOOST_STORAGE_POLICY \
apply_lambda< \
get_policy<policies_, storage_policy_tag, scalar_storage<_> >::type,
\
T \
>::type
...
class smart_ptr
: public optimally_inherit<
optimally_inherit<
BOOST_STORAGE_POLICY
...
{
public: // Policy types
typedef T element_type;
typedef BOOST_STORAGE_POLICY storage_policy;
and
namespace aux {
template< typename Policies, typename T >
struct storage_policy
{
typedef typename get_policy<
policies_
, storage_policy_tag
, scalar_storage<_>
>::type f_;
typedef typename apply_lambda<f_,T>::type type;
};
}
...
class smart_ptr
: public optimally_inherit<
optimally_inherit<
typename aux::storage_policy<policies_,T>::type
...
{
public: // Policy types
typedef T element_type;
typedef typename aux::storage_policy<policies_,T>::type
storage_policy;
is negligible, IMO (ignoring the fact that BOOST_STORAGE_POLICY is a macro
:).
> Two, what I didn't show is the template template version (which I left in
> for historical reasons).
> The usage is controlled by BOOST_SMART_POINTER_LEGACY_INTERFACE
OK, I see how that could warrant the existence of other macros besides
BOOST_SMART_POINTER_PARAMETERS. Thanks for elaborating.
[...]
> > [...]
> > Probably to have an associative container in MPL, but not
> > now :). Feel free to contribute, of course.
>
> Hmm...so if I understand correctly, I would add all the
> defaults to the container, then add the specified policies
> according to their categories, overwriting the default values.
> Then iterate over the container to get the final policies?
Yep, something like that. For instance,
namespace aux {
typedef mpl::map<
mpl::list<
scalar_storage<_>
, assert_check<_>
, ref_counted<_>
, disallow_conversion<_>
>
, get_category<_> // "key" function
> smart_ptr_default_params;
}
template<
typename DefaultParamsMap
, typename Params
>
struct params_map_gen
: mpl::fold<
Params
, DefaultParamsMap
, mpl::insert<_,_>
>
{
};
template <
typename T,
class P1 = empty_policy, class P2 = empty_policy,
class P3 = empty_policy, class P4 = empty_policy,
class params_map_ = typename params_map_gen<
aux::smart_ptr_default_params
, mpl::list<P1,P2,P3,P4>
>::type
>
class smart_ptr
: public optimally_inherit<
optimally_inherit<
typename aux::storage_policy<params_map_,T>::type
...
where 'storage_policy' is as simple as this:
template< typename PolicyMap, typename T >
struct storage_policy
{
typedef typename at<
PolicyMap
, storage_policy_tag
>::type f_;
typedef typename apply_lambda<f_,T>::type type;
};
> I might be able to hack a cheeseball metamap, though
> not a tree implementation (yet).
At this point I'm more interested in formulating an interface for
associative containers than their implementation qualities, so anything that
works will do.
Aleksey
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk