A small utility for template policy selection

Whilst working on a policy-based sparse-array class (which I hope to submit to Boost at some point), I had the problem that there did not seem to be any sensible way to organise the policies such that sensible defaults could be coded in the template. Rather than always forcing the users to specify the earlier policies, even when the default would be fine, simply because they wanted to use a different policy for one of the later parameters, I came up with the following little utility. =============================================================== #include <boost/mpl/find_if.hpp> #include <boost/mpl/deref.hpp> #include <boost/type_traits/is_base_of.hpp> using namespace boost; using namespace boost::mpl; template<typename Base, typename Types, typename DefType> class PolicySelector { private: typedef typename find_if< Types, is_base_of<Base,_1> >::type pos; typedef typename end<Types>::type end_pos; public: typedef typename if_< is_same<pos, end_pos>, DefType, typename deref<pos>::type >::type type; }; =============================================================== Basically, you pass a boost::mpl sequence in the Types argument (I usually use a mpl::vector), along with the base class for the policy classes and a default class to use if none is found otherwise, and the 'type' member gives the selected policy. The only restriction it imposes is that all classes implementing a particular policy type have to inherit from a single base class. A (slightly contrived :-) ) example to show how this is used: =============================================================== #include <boost/mpl/find_if.hpp> #include <boost/mpl/deref.hpp> #include <boost/type_traits/is_base_of.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/placeholders.hpp> #include <iostream> using namespace boost; using namespace boost::mpl; template<typename Base, typename Types, typename DefType> class PolicySelector { private: typedef typename find_if< Types, is_base_of<Base,_1> >::type pos; typedef typename end<Types>::type end_pos; public: typedef typename if_< is_same<pos, end_pos>, DefType, typename deref<pos>::type >::type type; }; class a_base { }; class a1 : public a_base { }; class a2 : public a_base { }; class a3 : public a1 { }; class b_base { }; class b1 : public b_base { }; class b2 : public b_base { }; class b3 : public b_base { }; // Select the 'A' policy. Default is a3. template<typename Types> class A_Selector { public: typedef typename PolicySelector< a_base , typename Types::type , a3>::type type; }; // Select the 'B' policy. Default is b2. template<typename Types> class B_Selector { public: typedef typename PolicySelector< b_base , typename Types::type , b2>::type type; }; // Utility class to ease building a mpl::vector. template<class p1=na, class p2=na> class sel_types { public: typedef typename vector<p1,p2>::type type; }; // Test class template. template<class Policies> class testit : public A_Selector<Policies>::type , public B_Selector<Policies>::type { public: typedef typename A_Selector<Policies>::type APolicy; typedef typename B_Selector<Policies>::type BPolicy; }; int main() { // Test policies listed in 'normal' order typedef testit<sel_types<a1, b1> > types1; typedef types1::APolicy A1; typedef types1::BPolicy B1; A1 aa1; std::cout << "Got " << typeid(aa1).name() << "\n"; std::cout << "Expected " << typeid(a1).name() << "\n"; B1 bb1; std::cout << "Got " << typeid(bb1).name() << "\n"; std::cout << "Expected " << typeid(b1).name() << "\n"; // Test missing 'B' policy - should use default typedef testit<sel_types<a2> > types2; typedef types1::APolicy A2; typedef types1::BPolicy B2; A2 aa2; std::cout << "Got " << typeid(aa2).name() << "\n"; std::cout << "Expected " << typeid(a2).name() << "\n"; B2 bb2; std::cout << "Got " << typeid(bb2).name() << "\n"; std::cout << "Expected " << typeid(b2).name() << "\n"; // Test missing 'A' policy - should use default typedef testit<sel_types<b1> > types3; typedef types1::APolicy A3; typedef types1::BPolicy B3; A3 aa3; std::cout << "Got " << typeid(aa3).name() << "\n"; std::cout << "Expected " << typeid(a3).name() << "\n"; B3 bb3; std::cout << "Got " << typeid(bb3).name() << "\n"; std::cout << "Expected " << typeid(b1).name() << "\n"; // Test policies in 'reversed' order. typedef testit<sel_types<b1, a1> > types4; typedef types1::APolicy A4; typedef types1::BPolicy B4; A4 aa4; std::cout << "Got " << typeid(aa4).name() << "\n"; std::cout << "Expected " << typeid(a1).name() << "\n"; B4 bb4; std::cout << "Got " << typeid(bb4).name() << "\n"; std::cout << "Expected " << typeid(b1).name() << "\n"; } =============================================================== As you can see, it doesn't matter which order the policies are specified in, nor whether they are specified at all. Would this utility be useful to anyone else? Is it worth my while writing up some proper documentation and submitting it for review? If so, which library would it go into? Spencer Collyer -- 12:47pm up 48 days 20:28, 21 users, load average: 0.09, 0.06, 0.13 Registered Linux User #232457 | LFS ID 11703

Spencer Collyer wrote:
Whilst working on a policy-based sparse-array class (which I hope to submit to Boost at some point), I had the problem that there did not seem to be any sensible way to organise the policies such that sensible defaults could be coded in the template. Rather than always forcing the users to specify the earlier policies, even when the default would be fine, simply because they wanted to use a different policy for one of the later parameters, I came up with the following little utility.
This looks like a very nice utility, and I'm sure it could find application. A library facing a similar problem is the iterator library, where the use_default mechanism was used. In this particular case, however, your method is not applicable as it is, because the parameters specified by use_default can be primitives. An alternative to the inheritance would be a policy_type metafunction: ============================================= BOOST_MPL_HAS_XXX_TRAIT_DEF(policy_type) struct not_a_policy {}; template <class P> struct policy_type { typedef BOOST_DEDUCED_TYPENAME if_< has_policy_type< P >, P::policy_type, not_a_policy >::type type; } ============================================= Your example could then be rewritten as: ============================================= struct a_policy {}; struct b_policy {}; struct a1 { typedef a_policy policy_type; } struct a2 {}; // External policy, have to externalize type: template<> struct policy_type<a2> { typedef a_policy type; }; struct a3 : public a1 {}; // Quick porting from your model struct b_base { typedef b_policy policy_type; } struct b1 : public b_base {}; struct b2 : public b_base {}; struct b3 : public b_base {}; ============================================= PolicySelector would be adapted like thus (I'll write typename instead of the boost macro): ============================================= namespace m = boost::mpl; template<typename Type, typename Policies, typename DefPolicy> class PolicySelector { private: typedef typename m::find_if< Policies, m::is_same< Type, typename policy_type<m::_1>::type > >::type pos; typedef typename m::end< Policies >::type end_pos; public: typedef typename m::if_< m::is_same< pos, end_pos >, DefPolicy, typename m::deref< pos >::type >::type type; }; ============================================= A_Selector thus becomes: ============================================= template< typename Policies > struct A_Selector { typedef typename PolicySelector< a_policy, Policies, a3>::type type; // I don't know why you had Types::type here in your example. }; ============================================= All other code should work unchanged. Sebastian Redl

Sebastian Redl wrote:
Spencer Collyer wrote:
Whilst working on a policy-based sparse-array class (which I hope to submit to Boost at some point), I had the problem that there did not seem to be any sensible way to organise the policies such that sensible defaults could be coded in the template. Rather than always forcing the users to specify the earlier policies, even when the default would be fine, simply because they wanted to use a different policy for one of the later parameters, I came up with the following little utility.
This looks like a very nice utility, and I'm sure it could find application. A library facing a similar problem is the iterator library, where the use_default mechanism was used. In this particular case, however, your method is not applicable as it is, because the parameters specified by use_default can be primitives.
The iterator library is different because it takes its template parameters individually, not as an MPL sequence. I'm working on a Named Template Parameters library which would address the needs of the iterator library. It's fully functional (passing 400-some tests) but the documentation is lagging. I literally just ran into a need for the policy selector this morning and was going to quickly code something up but Spencer beat me to it. :) I'd love to see something like this in Boost. It would complement NTP very nicely. -Dave

David Greene <greened@obbligato.org> writes:
Sebastian Redl wrote:
Spencer Collyer wrote:
The iterator library is different because it takes its template parameters individually, not as an MPL sequence. I'm working on a Named Template Parameters library which would address the needs of the iterator library. It's fully functional (passing 400-some tests) but the documentation is lagging.
I don't know if I told you this before, but it has been my intention, and Danial Wallin's, to integrate such a facility with Boost.Parameter, reusing much of the same code it already contains. I think doing a whole separate implementation would be a huge waste. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
I don't know if I told you this before, but it has been my intention, and Danial Wallin's, to integrate such a facility with Boost.Parameter, reusing much of the same code it already contains. I think doing a whole separate implementation would be a huge waste.
The implementation is done. It works. I have to fill out the documentation, which was waiting months due to some problems with BoostBook. The implementation has been done for quite a while. I don't consider it a waste at all. I looked at the Boost.Parameter implementation before but couldn't make heads or tails of it. We talked about Daniel doing some documentation but nothing came of it that I heard. If that's changed I'll be more than happy to look at integrating what I have. I do want to put up the current versions to get comments on the interfaces, at least. I just need some time when I'm _not_ fixing the hot water in my house. :-/ -Dave

"David A. Greene" <greened@obbligato.org> writes:
David Abrahams wrote:
I don't know if I told you this before, but it has been my intention, and Danial Wallin's, to integrate such a facility with Boost.Parameter, reusing much of the same code it already contains. I think doing a whole separate implementation would be a huge waste.
The implementation is done. It works. I have to fill out the documentation, which was waiting months due to some problems with BoostBook. The implementation has been done for quite a while. I don't consider it a waste at all.
It would be a waste to use separate code. Supporting NTP in Boost.Parameter would only take a very few small changes, and we plan to make them before the 1.34 freeze if possible.
I looked at the Boost.Parameter implementation before but couldn't make heads or tails of it. We talked about Daniel doing some documentation but nothing came of it that I heard. If that's changed I'll be more than happy to look at integrating what I have. I do want to put up the current versions to get comments on the interfaces, at least.
I think if you look at what we're planning, maybe we can have a productive debate about what the best interface is. A user might do something like this: namespace parameter = boost::parameter; // Declare a named template parameter wrapper template <class T = void> struct value_type_is : parameter::named_template_parameter<value_type_is<>, T> {}; template <class A0, class A1, class A2> struct foo { typedef parameter::parameters< value_type_is<> // more parameters listed here > foo_parameters; typedef typename foo_parameters::bind<A0,A1,A2>::type args; // Extract the value_type; the default is int typedef typename parameter::binding< args, value_type_is<>, int >::type value_type; }; foo<float, .., ..>::type == float foo<value_type_is<float>, .., ..>::type == float The beauty of this is that it will re-use all of the existing capabilities of the library, like positional and unnamed arguments (those that can be distinguished based on their properties and so don't need to be tagged explicitly). -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
I think if you look at what we're planning, maybe we can have a productive debate about what the best interface is.
I think that's a good idea. Here's what I have currently and I'll reply to your ideas after that. A complete example of use, from developer (of some template class) and user (of that class) perspective. I've cut non-ntp implementations out to save space. #include <boost/ntp/ntp.hpp> #include <boost/mpl/integral_c.hpp> #include <sys/time.h> #include <iostream> // Declare named template parameters BOOST_NTP (Elemtype); BOOST_NTP_C(Bufsize); BOOST_NTP_C(Stride); BOOST_NTP_C(Iterations); using namespace boost::ntp; using boost::mpl::integral_c; template<typename BufsizeOrNTP, typename ElemtypeOrNTP = default_<Elemtype, int >, typename StrideOrNTP = default_c<Stride, int, 1 >, typename IterationsOrNTP = default_c<Iterations, int, 100000> > class read_bandwidth_test { // Register all keys along with defaults (unfortunately redundant // with template parameter declarations above) typedef key_info< boost::mpl::vector<Bufsize, default_ <Elemtype, int >, default_c<Stride, int, 1 >, default_c<Iterations, int, 100000> >
info;
// Define scope of lookup (some params may not be NTPs) typedef boost::mpl::vector<BufsizeOrNTP, ElemtypeOrNTP, StrideOrNTP, IterationsOrNTP> params; public: // Get param values typedef typename lookup<Bufsize, params, info>::type BufsizeP; typedef typename lookup<Elemtype, params, info>::type ElemtypeP; typedef typename lookup<Stride, params, info>::type StrideP; typedef typename lookup<Iterations, params, info>::type IterationsP; static void run(void) { // Set up and walk through arrays }; }; // Pentium III 256k cache #define CACHE_SIZE (256 * 1024) // Cached test (note out-of-order params) typedef read_bandwidth_test<Elemtype_is <int >, Bufsize_is <int, CACHE_SIZE/2>, use_default_for<Stride >, use_default_for<Iterations> > cached_test; // Uncached test typedef read_bandwidth_test<Elemtype_is <int >, Bufsize_is <int, CACHE_SIZE*2>, use_default_for<Stride >, use_default_for<Iterations> > uncached_test; // This works too (default for Stride and Iterations) typedef read_bandwidth_test<Elemtype_is <int >, Bufsize_is <int, CACHE_SIZE*2> > uncached_test_2; // And this (alternate interface, doesn't require BOOST_NTP macros) typedef read_bandwidth_test<param <Elemtype, int >, param_c<Bufsize, int, CACHE_SIZE*2> > uncached_test_3; // And this (default for Stride and Iterations) typedef read_bandwidth_test<use_default, param <Elemtype, int >, param_c<Bufsize, int, CACHE_SIZE*2> > uncached_test_4; // And this (positional + named binding) typedef read_bandwidth_test<integral_c<int, CACHE_SIZE*2>, param <Elemtype, int > > uncached_test_5; // And this (positional defaults, integral_c bound to Bufsize) typedef read_bandwidth_test<param <Elemtype, int >, integral_c<int, CACHE_SIZE*2>, use_default, use_default> uncached_test_6; template<typename Test> void run_test(void) { // Keep track of time and calculate stats, etc. } int main(void) { run_test<cached_test>(); run_test<uncached_test>(); run_test<uncached_test_2>(); run_test<uncached_test_3>(); run_test<uncached_test_4>(); run_test<uncached_test_5>(); run_test<uncached_test_6>(); return(0); } My goals with this interface are: - Allow arbitrary reordering of parameters - Unspecified parameters use defaults automatically, regardless of position of other parameters - Can use positional notation for binding and named mechanism arbitrarily. - Ease of use for user (*_is for readability, etc.) - Ease of use for developer (though see my notes below) In one way or another, I've come across needs for all of these properties. The ability to arbitrarily reorder things and mix positional and named parameters is particularly useful when working with existing code. NTPs can be added incrementally without too much trouble.
A user might do something like this:
namespace parameter = boost::parameter;
// Declare a named template parameter wrapper template <class T = void> struct value_type_is : parameter::named_template_parameter<value_type_is<>, T> {}
This is what I use BOOST_NTP for. Of course it doesn't really matter what the underlying code looks like unless the user doesn't want to use macros for some reason. In the latter case, the interface I have allows the user to declare a named template parameter like this: strict Bufsize {}; The param<> notation at use then tells the NTP engine that this is a named template parameter. I prefer the macroized version myself because you get nice notation like Bufsize_is<> for free. I stole that from the original iterator_adaptors library. ;)
template <class A0, class A1, class A2> struct foo { typedef parameter::parameters< value_type_is<> // more parameters listed here > foo_parameters;
So far, this looks exactly like my interface.
typedef typename foo_parameters::bind<A0,A1,A2>::type args;
Here we differ. You use bind<> while I use key_info<>. I prefer the bind<> notation but I like the fact that key_info<> keeps parameters and defaults together in one place.
// Extract the value_type; the default is int typedef typename parameter::binding< args, value_type_is<>, int >::type value_type; };
So in my interface the programmer specifies defaults at declaration time while in yours she does it at lookup time. I think I like yours better. I'm trying to think of whether there are advantages of one over the other. A possible one is that in my scheme the programmer cannot accidentally specifiy two different default values for an NTP. In yours one could conceptually have two typedefs for value_type_is<>, one with a default of int and another with, say, float. I don't know why anyone would do this, though. I don't think it's a big deal. In your scheme, how does the developer of the template class specify defaults in the template parameter list declaration? The user ought to be able to pass only those parameters she really wants to change. The one thing I don't like about my interface is that this specification is redudant with what's passed to key_info<>.
foo<float, .., ..>::type == float foo<value_type_is<float>, .., ..>::type == float
I'm not sure what you're trying to convey here. It looks like you have both positional and named binding, which is good. Can the user name all templates except one, put the unnamed template anywhere and have it bind correctly? In my implementation, the user could specify one named parameter and three unnamed ones and the unnamed parameters will bind in the order of declaration, even though positionally they may not "align" with the declaration. For example: read_bandwidth_test<int, integral_c<int, 1>, integral_c<int, 100000>, Bufsize_is<int, CACHE_SIZE*2> > would bind Elemtype to int, Stride to 1 (mpl constant) and Iterations to 100000.
The beauty of this is that it will re-use all of the existing capabilities of the library, like positional and unnamed arguments (those that can be distinguished based on their properties and so don't need to be tagged explicitly).
I still don't completely understand unnamed arguments. Does my last example above cover what you mean? The first three parameters are not named but the naming of the last one defines the binding order for the others. I'm happy to help with an implementation based on named_parameters but as before I will need some documentation of internals so I can understand the code. -Dave

"David A. Greene" <greened@obbligato.org> writes:
David Abrahams wrote:
I think if you look at what we're planning, maybe we can have a productive debate about what the best interface is.
I think that's a good idea. Here's what I have currently and I'll reply to your ideas after that.
OK, I'll take a look on Friday. FYI, what we have is checked in to CVS already. -- Dave Abrahams Boost Consulting www.boost-consulting.com

"David A. Greene" <greened@obbligato.org> writes:
David Abrahams wrote:
I think if you look at what we're planning, maybe we can have a productive debate about what the best interface is.
I think that's a good idea. Here's what I have currently and I'll reply to your ideas after that.
A complete example of use, from developer (of some template class) and user (of that class) perspective. I've cut non-ntp implementations out to save space.
#include <boost/ntp/ntp.hpp> #include <boost/mpl/integral_c.hpp> #include <sys/time.h> #include <iostream>
// Declare named template parameters
BOOST_NTP (Elemtype); BOOST_NTP_C(Bufsize); BOOST_NTP_C(Stride); BOOST_NTP_C(Iterations);
I don't know what's under the covers of those macros; we've tried to make sure that there's a macro-less interface that's at least reasonably usable, so those would be: template <class T = int> struct Elemtype_is : parameter::template_keyword<a0_is<>, T> {}; I guess we don't have a keyword for non-type template parameters yet but the rest would be like: template <std::size_t n = 0> struct Bufsize_is : parameter::template_nontype_keyword<Bufsize_is<>, std::size_t, n> {}; How is your code dealing with the different types of nontype template parameters, e.g. std::size_t above?
using namespace boost::ntp; using boost::mpl::integral_c;
template<typename BufsizeOrNTP, typename ElemtypeOrNTP = default_<Elemtype, int >, typename StrideOrNTP = default_c<Stride, int, 1 >, typename IterationsOrNTP = default_c<Iterations, int, 100000> > class read_bandwidth_test {
Hm, interesting. What do these default_ things actually do? Isn't all the information after the first argument just ignored? Same question as above about non-type template parameters.
// Register all keys along with defaults (unfortunately redundant // with template parameter declarations above)
typedef key_info< boost::mpl::vector<Bufsize, default_ <Elemtype, int >, default_c<Stride, int, 1 >, default_c<Iterations, int, 100000> >
info;
Yeah, that is unfortunate. What's the point of the first set of declarations? We delay the the specification of defaults until the point of extraction. I suppose that has both upsides and downsides. Hmm; you're using mpl::vector -- are you doing anything to avoid O(N^2) instantiations for each parameter lookup?
// Define scope of lookup (some params may not be NTPs) typedef boost::mpl::vector<BufsizeOrNTP, ElemtypeOrNTP, StrideOrNTP, IterationsOrNTP> params;
In our case this would be typedef typename parameter::parameters< Bufsize_is<>, Elemtype_is<>, Stride_is<>, Iterations_is<> >::bind<BufsizeOrNTP,ElemtypeOrNTP,StrideOrNTP,IterationsOrNTP>::type params;
public:
// Get param values typedef typename lookup<Bufsize, params, info>::type BufsizeP;
And this is... a type? What is it, an mpl::int_<> ?
typedef typename lookup<Elemtype, params, info>::type ElemtypeP; typedef typename lookup<Stride, params, info>::type StrideP; typedef typename lookup<Iterations, params, info>::type IterationsP;
In our case (assuming we add support for non-type template parameters) this would be: typedef typename parameter::binding< params, Bufsize_is<> >::type BufsizeP; typedef typename parameter::binding< params, Elemtype_is<>, int >::type ElemtypeP; typedef typename parameter::binding< params, Stride_is<>, mpl::int_<1> >::type StrideP;
My goals with this interface are:
- Allow arbitrary reordering of parameters
- Unspecified parameters use defaults automatically, regardless of position of other parameters
I don't know what you mean by "automatically." I understand the second part of the sentence.
- Can use positional notation for binding and named mechanism arbitrarily.
I don't understand that at all.
- Ease of use for user (*_is for readability, etc.)
- Ease of use for developer (though see my notes below)
Doesn't look too easy for the developer. And IMO it would be better for the developer -- who is likely to want to use the parameter library anyway for function parameters -- to reuse his knowledge.
In one way or another, I've come across needs for all of these properties. The ability to arbitrarily reorder things and mix positional and named parameters is particularly useful when working with existing code. NTPs can be added incrementally without too much trouble.
The parameter library now supplies that. Additionally it has support for "unnamed" parameters (those whose identity can be deduced from the type passed) and the specification of MPL lambda expressions to identify the legal range of types for each parameter (with an error generated if required parameters can't be found).
A user might do something like this:
namespace parameter = boost::parameter;
// Declare a named template parameter wrapper template <class T = void> struct value_type_is : parameter::named_template_parameter<value_type_is<>, T> {}
This is what I use BOOST_NTP for. Of course it doesn't really matter what the underlying code looks like unless the user doesn't want to use macros for some reason.
It does matter. You're introducing declarations and definitions into the user's code. He needs to know what's going on.
In the latter case, the interface I have allows the user to declare a named template parameter like this:
strict Bufsize {}; ^ :)
The param<> notation at use then tells the NTP engine that this is a named template parameter.
I see no suuch notation.
I prefer the macroized version myself because you get nice notation like Bufsize_is<> for free. I stole that from the original iterator_adaptors library. ;)
Yes; we could add a macro easily enough.
template <class A0, class A1, class A2> struct foo { typedef parameter::parameters< value_type_is<> // more parameters listed here > foo_parameters;
So far, this looks exactly like my interface.
typedef typename foo_parameters::bind<A0,A1,A2>::type args;
Here we differ. You use bind<> while I use key_info<>.
I prefer the bind<> notation but I like the fact that key_info<> keeps parameters and defaults together in one place.
But it doesn't; the defaults are repeated and thus spread out.
// Extract the value_type; the default is int typedef typename parameter::binding< args, value_type_is<>, int >::type value_type; };
So in my interface the programmer specifies defaults at declaration time while in yours she does it at lookup time. I think I like yours better.
Haha! If there was one area in which I was prepared to consider that our interface could be improved on, it was that part.
I'm trying to think of whether there are advantages of one over the other. A possible one is that in my scheme the programmer cannot accidentally specifiy two different default values for an NTP. In yours one could conceptually have two typedefs for value_type_is<>, one with a default of int and another with, say, float. I don't know why anyone would do this, though. I don't think it's a big deal.
Agreed.
In your scheme, how does the developer of the template class specify defaults in the template parameter list declaration?
He passes parameter::void_. We're thinking of renaming that parameter::not_specified.
The user ought to be able to pass only those parameters she really wants to change.
Of course; that's supported. See libs/parameter/test/ntp.cpp
The one thing I don't like about my interface is that this specification is redudant with what's passed to key_info<>.
Yeah; why bother?
foo<float, .., ..>::type == float foo<value_type_is<float>, .., ..>::type == float
I'm not sure what you're trying to convey here. It looks like you have both positional and named binding, which is good.
Yes.
Can the user name all templates except one, put the unnamed template anywhere and have it bind correctly?
Yes. But let's call those "positional." In our terminology "unnamed" means something else (see above).
In my implementation, the user could specify one named parameter and three unnamed ones and the unnamed parameters will bind in the order of declaration, even though positionally they may not "align" with the declaration.
Ours works differently IIRC; positional parameters bind strictly by position. But I don't see this as being very important, though. Most languages that allow this sort of thing natively require that all positional parameters precede the named ones anyway and I don't see why a user would want to do otherwise.
For example:
read_bandwidth_test<int, integral_c<int, 1>, integral_c<int, 100000>, Bufsize_is<int, CACHE_SIZE*2> >
would bind Elemtype to int, Stride to 1 (mpl constant) and Iterations to 100000.
The beauty of this is that it will re-use all of the existing capabilities of the library, like positional and unnamed arguments (those that can be distinguished based on their properties and so don't need to be tagged explicitly).
I still don't completely understand unnamed arguments. Does my last example above cover what you mean?
No, please see http://www.boost.org/libs/python/doc/v2/class.html#class_-spec for an example. This predates the parameter library; if I can find the time I'm going to go through Boost.Python and parameter-ize everything.
The first three parameters are not named but the naming of the last one defines the binding order for the others.
I'm happy to help with an implementation based on named_parameters but as before I will need some documentation of internals so I can understand the code.
I hope you don't feel your efforts have gone to waste, but I don't think there's much left to do. From my point-of-view, it was not a waste at all because it prodded us to get the NTP feature done in Boost.Parameter. Daniel tells me you wrote over 400 tests for your library! It might be a great contribution if the logic of those tests could be reworked to test Boost.Parameter instead. At the very least we'd discover if we were missing anything important provided in your work. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 2/10/06, David Abrahams <dave@boost-consulting.com> wrote: [snip]
I hope you don't feel your efforts have gone to waste, but I don't think there's much left to do. From my point-of-view, it was not a waste at all because it prodded us to get the NTP feature done in Boost.Parameter. Daniel tells me you wrote over 400 tests for your library! It might be a great contribution if the logic of those tests could be reworked to test Boost.Parameter instead. At the very least we'd discover if we were missing anything important provided in your work.
Will this NTP feature in parameter library be on the 1.34 release? I'm desperately needing this.
-- Dave Abrahams Boost Consulting www.boost-consulting.com
Thanks, -- Felipe Magno de Almeida

Felipe Magno de Almeida <felipe.m.almeida@gmail.com> writes:
On 2/10/06, David Abrahams <dave@boost-consulting.com> wrote:
[snip]
I hope you don't feel your efforts have gone to waste, but I don't think there's much left to do. From my point-of-view, it was not a waste at all because it prodded us to get the NTP feature done in Boost.Parameter. Daniel tells me you wrote over 400 tests for your library! It might be a great contribution if the logic of those tests could be reworked to test Boost.Parameter instead. At the very least we'd discover if we were missing anything important provided in your work.
Will this NTP feature in parameter library be on the 1.34 release? I'm desperately needing this.
Yes, it's already in the main trunk of CVS. See libs/parameter/test/ntp.cpp Don't be distracted by the function types there; they're just used to assemble all the parameter results and easily test that we have what we expected. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 2/13/06, David Abrahams <dave@boost-consulting.com> wrote: [snip]
Yes, it's already in the main trunk of CVS. See libs/parameter/test/ntp.cpp
Thanks! BTW, I'm not being able to access the cvs through pserver (anonymously), it is been 3 days. cvs -d:pserver:anonymous@cvs.sf.net:/cvsroot/boost login CVS password: [enter] cvs [login aborted]: end of file from server (consult above messages if any) The same happens for cvs.sourceforge.net
Don't be distracted by the function types there; they're just used to assemble all the parameter results and easily test that we have what we expected.
Ok!
-- Dave Abrahams Boost Consulting www.boost-consulting.com
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
-- Felipe Magno de Almeida

| -----Original Message----- | From: boost-bounces@lists.boost.org | [mailto:boost-bounces@lists.boost.org] On Behalf Of Felipe | Magno de Almeida | Sent: 14 February 2006 17:49 | To: boost@lists.boost.org | Subject: Re: [boost] A small utility for template policy selection | | BTW, I'm not being able to access the cvs through pserver | (anonymously), it is been 3 days. | | cvs -d:pserver:anonymous@cvs.sf.net:/cvsroot/boost login | CVS password: [enter] | cvs [login aborted]: end of file from server (consult above messages if any) I get similar just now: C:\Program Files\Microsoft Visual Studio 8\VC>cvs -d:pserver:anonymous@cvs.sf.ne t:/cvsroot/boost login Logging in to :pserver:anonymous@cvs.sf.net:2401/cvsroot/boost CVS password: cvs [login aborted]: connect to cvs.sf.net(66.35.250.207):2401 failed: Connectio n timed out Some weeks ago I had the same problem and eventually raised a query at sourceforge and then 'magically' it started working again a couple of days later. suggest you try this? ( I hope to use this soon ;-) ) Paul -- Paul A Bristow Prizet Farmhouse, Kendal, Cumbria UK LA8 8AB Phone and SMS text +44 1539 561830, Mobile and SMS text +44 7714 330204 mailto: pbristow@hetp.u-net.com http://www.hetp.u-net.com/index.html http://www.hetp.u-net.com/Paul%20A%20Bristow%20info.html

Felipe Magno de Almeida <felipe.m.almeida@gmail.com> writes:
On 2/13/06, David Abrahams <dave@boost-consulting.com> wrote:
[snip]
Yes, it's already in the main trunk of CVS. See libs/parameter/test/ntp.cpp
Thanks! BTW, I'm not being able to access the cvs through pserver (anonymously), it is been 3 days.
cvs -d:pserver:anonymous@cvs.sf.net:/cvsroot/boost login CVS password: [enter] cvs [login aborted]: end of file from server (consult above messages if any)
The same happens for cvs.sourceforge.net
You can always get http://www.boost-consulting.com/boost.tar.bz2 HTH, -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 2/13/06, David Abrahams <dave@boost-consulting.com> wrote: [snip]
Yes, it's already in the main trunk of CVS. See libs/parameter/test/ntp.cpp
Is this a typo? template <class T = int> struct a3_is : parameter::template_keyword<a2_is<>, T> ^ typo? {}; Defining a3_is template and passing a2_is as argument to template_keyword. [snip]
-- Dave Abrahams Boost Consulting www.boost-consulting.com
-- Felipe Magno de Almeida

Felipe Magno de Almeida <felipe.m.almeida@gmail.com> writes:
On 2/13/06, David Abrahams <dave@boost-consulting.com> wrote:
[snip]
Yes, it's already in the main trunk of CVS. See libs/parameter/test/ntp.cpp
Is this a typo?
template <class T = int> struct a3_is : parameter::template_keyword<a2_is<>, T> ^ typo? {};
Defining a3_is template and passing a2_is as argument to template_keyword.
Huh; looks like a mistake to me. Daniel? -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams wrote:
The following message is a courtesy copy of an article that has been posted to gmane.comp.lib.boost.devel as well.
Felipe Magno de Almeida <felipe.m.almeida@gmail.com> writes:
On 2/13/06, David Abrahams <dave@boost-consulting.com> wrote:
[snip]
Yes, it's already in the main trunk of CVS. See libs/parameter/test/ntp.cpp Is this a typo?
template <class T = int> struct a3_is : parameter::template_keyword<a2_is<>, T> ^ typo? {};
Defining a3_is template and passing a2_is as argument to template_keyword.
Huh; looks like a mistake to me. Daniel?
Yes, it's a mistake. Good catch. -- Daniel Wallin

David, thanks for your comments, they are very good. I'll look them over and respond tonight when I have more time to formulate meaningful answers. David Abrahams wrote:
I hope you don't feel your efforts have gone to waste, but I don't think there's much left to do. From my point-of-view, it was not a waste at all because it prodded us to get the NTP feature done in Boost.Parameter.
I don't feel the effort was wasted. Two of my personal goals for doing it was to spur getting NTPs into Boost but also to have a vehicle for me to learn about mpl. The former seems to have been accomplished and the latter most definitely was. :)
Daniel tells me you wrote over 400 tests for your library! It might be a great contribution if the logic of those tests could be reworked to test Boost.Parameter instead. At the very least we'd discover if we were missing anything important provided in your work.
I didn't actually write 400 tests, the computer did. :) I have a Perl script that walks through all possible combinations of specifying (or not) parameter values for a three-argument template. I could probably adapt the script for named_parameters fairly easily once I understand the interfaces. Given my brief scan of your comments it probably won't generate 400 tests because my understanding is that there are some restrictions in your implementation about how unnamed/positional parameters are bound. That's not a criticism, just something to keep in mind when counting tests. -Dave

David Abrahams wrote:
BOOST_NTP (Elemtype); BOOST_NTP_C(Bufsize); BOOST_NTP_C(Stride); BOOST_NTP_C(Iterations);
I don't know what's under the covers of those macros; we've tried to make sure that there's a macro-less interface that's at least reasonably usable, so those would be:
template <class T = int> struct Elemtype_is : parameter::template_keyword<a0_is<>, T> {};
I was concentrating on interface in my message. The macros are defined like this: /// NTP support macro to provide key_is<value> flavor #define BOOST_NTP(key) \ struct key {}; \ template<typename Type> \ class key ## _is : public boost::ntp::param<key, Type> {}; /// NTP support macro to provide key_is<value> flavor for non-type NTPs #define BOOST_NTP_C(key) \ struct key {}; \ template<typename Type, Type Value> \ class key ## _is : public boost::ntp::param_c<key, Type, Value> {}; It's very close to what you specified. I just find something less wordy easier to comprehend. I don't know what a0_is<> is, for example.
I guess we don't have a keyword for non-type template parameters yet but the rest would be like:
template <std::size_t n = 0> struct Bufsize_is : parameter::template_nontype_keyword<Bufsize_is<>, std::size_t, n> {};
How is your code dealing with the different types of nontype template parameters, e.g. std::size_t above?
I punted on nontype template parameters. I don't know how to do this. I just wrapped everything in mpl::integral_c to turn it into a type. If you're asking for how to handle a situation like this: template<int arg1, int arg3, int arg3> class foo { // Do something to extract args as named parameters } then I don't know. I hadn't thought about it.
using namespace boost::ntp; using boost::mpl::integral_c;
template<typename BufsizeOrNTP, typename ElemtypeOrNTP = default_<Elemtype, int >, typename StrideOrNTP = default_c<Stride, int, 1 >, typename IterationsOrNTP = default_c<Iterations, int, 100000> > class read_bandwidth_test {
Hm, interesting. What do these default_ things actually do? Isn't all the information after the first argument just ignored? Same question as above about non-type template parameters.
default_<> is one way the NTP engine discovers whether a passed parameter is a named template parameter (versus a positional one). *_is and param<> are the other ways of identifying NTPs. I put the default initializers in the class declaration so the user would not have to fill in all of the template parameters every time. This way they default to whatever value is bound by default_<>. The only thing that needs to be explicitly specified in this example is Bufsize, which can be done with either a named or positional parameter.
// Register all keys along with defaults (unfortunately redundant // with template parameter declarations above)
typedef key_info< boost::mpl::vector<Bufsize, default_ <Elemtype, int >, default_c<Stride, int, 1 >, default_c<Iterations, int, 100000> >
info;
Yeah, that is unfortunate. What's the point of the first set of declarations? We delay the the specification of defaults until the point of extraction. I suppose that has both upsides and downsides.
As stated above, the motivation is to let the user know what arguments are default in the class template interface and which parameters must be specified, just like with regular old templates. How is this done in named_parameters?
Hmm; you're using mpl::vector -- are you doing anything to avoid O(N^2) instantiations for each parameter lookup?
:) I knew that wouldn't get past you. I was concentrating on getting things to work. Optimization was going to be phase II.
// Define scope of lookup (some params may not be NTPs) typedef boost::mpl::vector<BufsizeOrNTP, ElemtypeOrNTP, StrideOrNTP, IterationsOrNTP> params;
In our case this would be
typedef typename parameter::parameters< Bufsize_is<>, Elemtype_is<>, Stride_is<>, Iterations_is<> >::bind<BufsizeOrNTP,ElemtypeOrNTP,StrideOrNTP,IterationsOrNTP>::type params;
Can you explain a bit about what this means? What does the binding do, exactly?
public:
// Get param values typedef typename lookup<Bufsize, params, info>::type BufsizeP;
And this is... a type? What is it, an mpl::int_<> ?
Yep, exactly.
typedef typename lookup<Elemtype, params, info>::type ElemtypeP; typedef typename lookup<Stride, params, info>::type StrideP; typedef typename lookup<Iterations, params, info>::type IterationsP;
In our case (assuming we add support for non-type template parameters) this would be:
typedef typename parameter::binding< params, Bufsize_is<> >::type BufsizeP;
As I said, I like this syntax better than mine. Here's the difference between our approaches: In my case, I opted to make "params" a simple sequence of all of the parameters passed to the template (the formal arguments that participate in NTP binding) while "info" specifies the mapping of NTP names to defaults, or in the case of Bufsize, the fact that it doesn't have a default. If I understand your interface correctly, "params" holds both the formal arguments that participate in NTP binding and the NTP names. Default specification occurs at lookup time. We've just separated steps a little bit differently. Right now I don't have a strong preference for either, though I would like to understand the purpose of parameters<>::bind<> better. What kind of binding is being done?
typedef typename parameter::binding< params, Elemtype_is<>, int >::type ElemtypeP;
typedef typename parameter::binding< params, Stride_is<>, mpl::int_<1> >::type StrideP;
As I understand it, this both specifies defaults and does the actual mapping between actual arguments and NTP names.
My goals with this interface are:
- Allow arbitrary reordering of parameters
- Unspecified parameters use defaults automatically, regardless of position of other parameters
I don't know what you mean by "automatically." I understand the second part of the sentence.
Poor choice of words on my part. This is really two different goals: - Show which NTPs have defaults right in the template interface so it's clear to the user without having to look at the use of the binding mechanism. - Map all unspecified parameters to their defaults, either because they don't appear in the actual arguments or because the "use_default" positional parameter appears.
- Can use positional notation for binding and named mechanism arbitrarily.
I don't understand that at all.
Yeah, that makes no sense at all. :) What I was attempting to convey more concisely than I should have is the algorithm for binding. Here it is, right from the sources, with additional (hopefully) clarifying comments: // Match up given params to the key info. Matches are made according // to the following algorithm: // 1. Specified parameters are matched to the key info. This // includes explicit defaults. That is, all actual arguments passed with *_is get bound as expected. // 2. Remaining keys are ordered as specified in the key info. // Remaining unnamed parameters are ordered as specified in // the param list. Match up each parameter in order with the // keys. Any template parameters that aren't of the form *_is (that is, positional parameters) get bound in the order that they appear in key_info. The assumption is that the class template developer will be nice and list them in the same order as in the template declaration. So if I have int, long and double actual arguments and foo, bar and baz are listed in key_info in that order, foo will get bound to int, bar to long and baz to double. // 3. All remaining parameters are implicit defaults. Match // up with remaining unmatched keys. These parameter names don't appear in the actual arguments and we've run out of positional parameters. Everything else is bound to its default.
- Ease of use for user (*_is for readability, etc.)
- Ease of use for developer (though see my notes below)
Doesn't look too easy for the developer. And IMO it would be better for the developer -- who is likely to want to use the parameter library anyway for function parameters -- to reuse his knowledge.
Agreed about reusing knowledge, but what do you find not easy, or less easy? I find some of the named_parameters syntax rather unwieldy. It's probably a matter of personal taste. These are complicated problems to solve and sometimes have complicated solutions.
In one way or another, I've come across needs for all of these properties. The ability to arbitrarily reorder things and mix positional and named parameters is particularly useful when working with existing code. NTPs can be added incrementally without too much trouble.
The parameter library now supplies that. Additionally it has support for "unnamed" parameters (those whose identity can be deduced from the type passed) and the specification of MPL lambda expressions to identify the legal range of types for each parameter (with an error generated if required parameters can't be found).
Yes, unnamed parameters are a missing piece of my work.b Can you give an example of the lambda expressions to specify legal types? That sounds very useful.
A user might do something like this:
namespace parameter = boost::parameter;
// Declare a named template parameter wrapper template <class T = void> struct value_type_is : parameter::named_template_parameter<value_type_is<>, T> {}
This is what I use BOOST_NTP for. Of course it doesn't really matter what the underlying code looks like unless the user doesn't want to use macros for some reason.
It does matter. You're introducing declarations and definitions into the user's code. He needs to know what's going on.
Point taken. I guess I wrote the macros to do pretty much what I would have expected them to do. They exist to provide a simpler interface. Their effect would obviously be documented just like with any other interface. I tend to shy away from macros myself, but in this case, it really saves a lot of typing and potentially nasty template syntax.
In the latter case, the interface I have allows the user to declare a named template parameter like this:
strict Bufsize {};
^ :)
Hopefully the point got across. :)
The param<> notation at use then tells the NTP engine that this is a named template parameter.
I see no suuch notation.
Sorry, I should have been more complete. If the user doesn't want to use macros, he can do this: struct Key1 {}; struct Key2 {}; struct Key3 {}; typedef tester<boost::ntp::param<Key1, long >, boost::ntp::param<Key2, int >, boost::ntp::param<Key3, double> > blah; With macros it would be typedef tester<Key1_is<long >, Key2_is<int >, Key3_is<double> > blech;
I prefer the macroized version myself because you get nice notation like Bufsize_is<> for free. I stole that from the original iterator_adaptors library. ;)
Yes; we could add a macro easily enough.
Sounds good!
typedef typename foo_parameters::bind<A0,A1,A2>::type args;
Here we differ. You use bind<> while I use key_info<>.
I prefer the bind<> notation but I like the fact that key_info<> keeps parameters and defaults together in one place.
But it doesn't; the defaults are repeated and thus spread out.
Yes, they are repeated, but the defaults appear with the specification of which formal arguments participate in NTP binding.
// Extract the value_type; the default is int typedef typename parameter::binding< args, value_type_is<>, int >::type value_type; };
So in my interface the programmer specifies defaults at declaration time while in yours she does it at lookup time. I think I like yours better.
Haha! If there was one area in which I was prepared to consider that our interface could be improved on, it was that part.
:) What were you thinking of, exactly? It would be helpful to see an example of how named_parameters uses defaults in the template declaration to allow the user to avoid specifying NTP names that should bind to defaults in the actual arguments.
In your scheme, how does the developer of the template class specify defaults in the template parameter list declaration?
He passes parameter::void_. We're thinking of renaming that parameter::not_specified.
Ok, that looks good.
The user ought to be able to pass only those parameters she really wants to change.
Of course; that's supported. See libs/parameter/test/ntp.cpp
Haven't had a chance to peek yet.
The one thing I don't like about my interface is that this specification is redudant with what's passed to key_info<>.
Yeah; why bother?
Looking back over my testcases (just one of them! :) ) I see that I misspoke about how defaults are specified. The class template in this particular testcase looks like this: template<typename Param1 = boost::ntp::default_tag, typename Param2 = boost::ntp::default_tag, typename Param3 = boost::ntp::default_tag> class tester { private: typedef tester<Param1, Param2, Param3> This; typedef boost::ntp::key_info< boost::mpl::vector<boost::ntp::default_c<Key1, long, 1>, boost::ntp::default_c<Key2, long, 2>, boost::ntp::default_c<Key3, long, 3> >
Info;
typedef boost::mpl::vector<Param1, Param2, Param3> Params; public: typedef typename boost::ntp::lookup<Key1, Params, Info>::type Key1Type; typedef typename boost::ntp::lookup<Key2, Params, Info>::type Key2Type; typedef typename boost::ntp::lookup<Key3, Params, Info>::type Key3Type; enum { value1 = Key1Type::value, value2 = Key2Type::value, value3 = Key3Type::value, }; tester(boost::test_toolbox::output_test_stream &out, const std::string &name) { out << name << std::endl; out << "Value1: " << value1 << std::endl; out << "Value2: " << value2 << std::endl; out << "Value3: " << value3 << std::endl; }; }; The bandwidth test example I posted was somewhat out of date. It still works, but the duplicate defaults are not required. This looks just like your use of parameter::not_specified.
Can the user name all templates except one, put the unnamed template anywhere and have it bind correctly?
Yes. But let's call those "positional." In our terminology "unnamed" means something else (see above).
Yes, "positional" is a better term.
In my implementation, the user could specify one named parameter and three unnamed ones and the unnamed parameters will bind in the order of declaration, even though positionally they may not "align" with the declaration.
Ours works differently IIRC; positional parameters bind strictly by position. But I don't see this as being very important, though. Most languages that allow this sort of thing natively require that all positional parameters precede the named ones anyway and I don't see why a user would want to do otherwise.
So how does something like this work: template<typename A = parameters::unspecified, typename B = parameters::unspecified, typename C = parameters::unspecified> class Foo { ... }; typedef Foo<int, long, A_is<double> > myfoo; Is this just not allowed? I would expect B to be bound to int and C to long.
I still don't completely understand unnamed arguments. Does my last example above cover what you mean?
No, please see http://www.boost.org/libs/python/doc/v2/class.html#class_-spec for an example. This predates the parameter library; if I can find the time I'm going to go through Boost.Python and parameter-ize everything.
Ok, I think I get it now. I see how it would be quite useful. I'll see if I can get some time this weekend to download the parameters library with NTPs and see about modifying my Perl script to generate tests. No promises I'll have anything by Monday, though! ;) -Dave

"David A. Greene" <greened@obbligato.org> writes:
David Abrahams wrote:
BOOST_NTP (Elemtype);
Sorry, Daniel Wallin is working on a reply to this. Apparently he was very close to completing it today, but he must've run out of steam :) Something will be forthcoming RSN. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David A. Greene wrote:
David Abrahams wrote:
BOOST_NTP (Elemtype); BOOST_NTP_C(Bufsize); BOOST_NTP_C(Stride); BOOST_NTP_C(Iterations);
I don't know what's under the covers of those macros; we've tried to make sure that there's a macro-less interface that's at least reasonably usable, so those would be:
template <class T = int> struct Elemtype_is : parameter::template_keyword<a0_is<>, T> {};
[...]
It's very close to what you specified. I just find something less wordy easier to comprehend. I don't know what a0_is<> is, for example.
a0_is<> was a typo, it's supposed to be: template <class T = int> struct Elemtype_is : parameter::template_keyword<Elemtype_is<>, T> {}; The point of the T's default value is that we can use Elemtype_is<> as a tag-type for the parameter, instead of having a separate tag. [...]
If I understand your interface correctly, "params" holds both the formal arguments that participate in NTP binding and the NTP names. Default specification occurs at lookup time.
We've just separated steps a little bit differently. Right now I don't have a strong preference for either, though I would like to understand the purpose of parameters<>::bind<> better. What kind of binding is being done?
parameters<>::bind<> returns an ArgumentPack with keyword tags bound to actual argument types. This ArgumentPack can then be queried for keyword tags with binding<>.
typedef typename parameter::binding< params, Elemtype_is<>, int >::type ElemtypeP;
typedef typename parameter::binding< params, Stride_is<>, mpl::int_<1> >::type StrideP;
As I understand it, this both specifies defaults and does the actual mapping between actual arguments and NTP names.
Yes. It's actually quite important to specify the default as late as possible, because defaults can depend on the values of other arguments.
My goals with this interface are:
- Allow arbitrary reordering of parameters
- Unspecified parameters use defaults automatically, regardless of position of other parameters
I don't know what you mean by "automatically." I understand the second part of the sentence.
Poor choice of words on my part. This is really two different goals:
- Show which NTPs have defaults right in the template interface so it's clear to the user without having to look at the use of the binding mechanism.
This sounds like a good job for documentation. As I mentioned above, specifying defaults this early means you can't have default dependencies.
Doesn't look too easy for the developer. And IMO it would be better for the developer -- who is likely to want to use the parameter library anyway for function parameters -- to reuse his knowledge.
Agreed about reusing knowledge, but what do you find not easy, or less easy? I find some of the named_parameters syntax rather unwieldy.
What part of the syntax specifically?
The parameter library now supplies that. Additionally it has support for "unnamed" parameters (those whose identity can be deduced from the type passed) and the specification of MPL lambda expressions to identify the legal range of types for each parameter (with an error generated if required parameters can't be found).
Yes, unnamed parameters are a missing piece of my work.b Can you give an example of the lambda expressions to specify legal types? That sounds very useful.
An example could be something that uses policies. Here we can use a lambda expression to automatically bind the arguments: ... template < class Policy0 = parameter::void_, class Policy1 = parameter::void_
struct thing { typedef parameter::parameters< unnamed< policy0_is<> , is_base_and_derived<policy0_tag, mpl::_> > , unnamed< policy1_is<> , is_base_and_derived<policy1_tag, mpl::_> > > parameters; typedef typename parameters::bind<Policy0,Policy1>::type args; }; struct my_policy : policy1_tag {}; thing<my_policy> // policy1_is<> is bound to my_policy
Ours works differently IIRC; positional parameters bind strictly by position. But I don't see this as being very important, though. Most languages that allow this sort of thing natively require that all positional parameters precede the named ones anyway and I don't see why a user would want to do otherwise.
So how does something like this work:
template<typename A = parameters::unspecified, typename B = parameters::unspecified, typename C = parameters::unspecified> class Foo { ... };
typedef Foo<int, long, A_is<double> > myfoo;
Is this just not allowed?
No, it's an error. We bind strictly by absolute position. A will be bound to two types, int and double.
I would expect B to be bound to int and to long.
Well, that would complicate the implementation quite a lot. And probably decrease efficiency. We recommend that users use "positional first".
I still don't completely understand unnamed arguments. Does my last example above cover what you mean? No, please see http://www.boost.org/libs/python/doc/v2/class.html#class_-spec for an example. This predates the parameter library; if I can find the time I'm going to go through Boost.Python and parameter-ize everything.
Ok, I think I get it now. I see how it would be quite useful.
I'll see if I can get some time this weekend to download the parameters library with NTPs and see about modifying my Perl script to generate tests. No promises I'll have anything by Monday, though! ;)
Great! -- Daniel Wallin

Daniel Wallin <dalwan01@student.umu.se> writes:
David A. Greene wrote:
David Abrahams wrote:
BOOST_NTP (Elemtype); BOOST_NTP_C(Bufsize); BOOST_NTP_C(Stride); BOOST_NTP_C(Iterations);
I don't know what's under the covers of those macros; we've tried to make sure that there's a macro-less interface that's at least reasonably usable, so those would be:
template <class T = int> struct Elemtype_is : parameter::template_keyword<a0_is<>, T> {};
[...]
It's very close to what you specified. I just find something less wordy easier to comprehend. I don't know what a0_is<> is, for example.
a0_is<> was a typo, it's supposed to be:
template <class T = int> struct Elemtype_is : parameter::template_keyword<Elemtype_is<>, T> {};
The point of the T's default value is that we can use Elemtype_is<> as a tag-type for the parameter, instead of having a separate tag.
It's a cute trick but I'm not sure we should be doing it. It permits the user a usage that I wouldn't want to encourage (i.e. she can leave out the template argument) and looks a little misleading, as though we're establishing the default for Elemtype.
typedef typename parameter::binding< params, Elemtype_is<>, int >::type ElemtypeP;
typedef typename parameter::binding< params, Stride_is<>, mpl::int_<1> >::type StrideP;
As I understand it, this both specifies defaults and does the actual mapping between actual arguments and NTP names.
Yes. It's actually quite important to specify the default as late as possible, because defaults can depend on the values of other arguments.
A very good point. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On Wed, 01 Feb 2006 17:14:59 +0100, Sebastian Redl wrote:
This looks like a very nice utility, and I'm sure it could find application. A library facing a similar problem is the iterator library, where the use_default mechanism was used. In this particular case, however, your method is not applicable as it is, because the parameters specified by use_default can be primitives.
I designed PolicySelector to work with policy classes, so didn't think about primitive types when writing it.
An alternative to the inheritance would be a policy_type metafunction:
I'll need to study the code you presented a bit more to understand it. The way I saw it working was that, if the user had some pre-existing policy class they wanted to use, they could wrap it up in another class that inherited from the base class, and just forwarded all operations on. Given I like to keep interfaces to policy classes small, this didn't seem too much of an overhead to me.
A_Selector thus becomes: ============================================= template< typename Policies > struct A_Selector { typedef typename PolicySelector< a_policy, Policies, a3>::type type; // I don't know why you had Types::type here in your example. }; =============================================
If I didn't have the 'typename Types::type' in the selectors, the code didn't work - it always gave the default. An alternative would have been to put it in the PolicySelector itself, which probably would make future users' lives easier. If it looks like there is more interest in this, I'll make that change and send a modified example to the list. Thanks for the feedback. Spencer Collyer -- 10:49am up 49 days 18:31, 20 users, load average: 0.10, 0.11, 0.38 Registered Linux User #232457 | LFS ID 11703

Spencer Collyer wrote:
I'll need to study the code you presented a bit more to understand it. The way I saw it working was that, if the user had some pre-existing policy class they wanted to use, they could wrap it up in another class that inherited from the base class, and just forwarded all operations on. Given I like to keep interfaces to policy classes small, this didn't seem too much of an overhead to me.
Well, if you have an external metafunction, you only need to specialize it. No need to write a wrapper. That's the main reason I suggested the metafunction. Sebastian Redl

Sebastian, Sorry for the delay in replying, but I've been tied up with other projects for a while (like trying to find my next contract :-) ), so I've not had the time to get back to this. Just a quick note to say that I like your idea, and I'm going to rework my proposal to try and use it. Spencer Collyer -- <<< Eagles may soar, but weasels don't get sucked into jet engines >>> 7:46am up 62 days 15:28, 23 users, load average: 0.20, 0.08, 0.10 Registered Linux User #232457 | LFS ID 11703
participants (8)
-
Daniel Wallin
-
David A. Greene
-
David Abrahams
-
David Greene
-
Felipe Magno de Almeida
-
Paul A Bristow
-
Sebastian Redl
-
Spencer Collyer