
I see that a Named Params library has been accepted into Boost. Great! Is this named template params or named function params? I've actually been working on a named template params implementation of my own so I'm particularly curious about what Dave and Daniel have done, whether it be for templates or functions. Is there an accessible page of documentation somewhere? There's been a named_template_params.hpp in the sandbox for a long time. What's going on with that? Is there general interest in a named template parameters library? -Dave

David Greene wrote:
I see that a Named Params library has been accepted into Boost. Great!
Is this named template params or named function params?
Function parameters.
I've actually been working on a named template params implementation of my own so I'm particularly curious about what Dave and Daniel have done, whether it be for templates or functions.
Is there an accessible page of documentation somewhere?
There's been a named_template_params.hpp in the sandbox for a long time. What's going on with that? Is there general interest in a named template parameters library?
There has already been a released named_template_params.hpp in boost/detail "forever". http://www.boost.org/boost/detail/named_template_params.hpp IMO named template parameters are unweildy in C++. I prefer "unnamed template parameters" like those described in http://www.boost.org/libs/python/doc/v2/class.html As a matter of fact, I was just looking into how to extend our named parameters library to handle unnamed function parameters. http://www.boost.org/libs/python/doc/v2/def.html -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Is there an accessible page of documentation somewhere?
Thanks. Looks very cool.
There has already been a released named_template_params.hpp in boost/detail "forever". http://www.boost.org/boost/detail/named_template_params.hpp
I know this used to be used by the old iterator_adaptors. I can't quite remember what the interface to named_template_params was and it's a little difficult for me to envision given just the header file. Got an example laying around somewhere?
IMO named template parameters are unweildy in C++. I prefer "unnamed template parameters" like those described in http://www.boost.org/libs/python/doc/v2/class.html
"Boost.Python determines the role of the argument from its type." So does that mean that this idiom can only be used when each argument is of a distinct type? I realize that this can be made to happen by wrapping each argument in a unique class, but isn't that exactly what named template parameters is? The use of what I've got working now is shown below. Things I don't like about this include: - Necessity of passing key_info<> to lookup<>. I tried to do this through default template args but I couldn't come up with a working solution. - The separation of parameter declaration and default value definition. - Packaging up all parameters into an MPL sequence. It's not so bad, though. Would anyone find this useful? Obviously it will need some work. I'd like to clean up the syntax some if possible. -Dave ----------------------------------- #include <libcwd/sys.h> #include <libcwd/type_info.h> #include <ntp.hh> #include <io.hh> #include <boost/mpl/map.hpp> #include <boost/mpl/int.hpp> #include <iostream> MPIO_DECLARE_FILE(ntp_example_cc); struct Key1; struct Key2; struct Key3; template<typename Param1 = ntp::default_tag, typename Param2 = ntp::default_tag, typename Param3 = ntp::default_tag> class tester { private: typedef tester<Param1, Param2, Param3> This; // Declare all keys and any default values typedef ntp::key_info<ntp::default_c<Key1, long, 1>, ntp::default_c<Key2, long, 2>, ntp::default_c<Key3, long, 3> > Keys; typedef boost::mpl::vector<Param1, Param2, Param3> Params; struct debug { mpio::print<Params, MPIO_FILE_LINE(ntp_example_cc)> print_params; }; // If these are uncommented then the compiler will spew out a bunch // of messages. #ifdef CT_DEBUG debug print_tester; typename ntp::key_info<ntp::default_c<Key1, long, 1>, ntp::default_c<Key2, long, 2>, ntp::default_c<Key3, long, 3> >::debug print_key_info; typename ntp::lookup<Key1, Params, Keys>::debug print_lookup1; typename ntp::lookup<Key2, Params, Keys>::debug print_lookup2; typename ntp::lookup<Key3, Params, Keys>::debug print_lookup3; #endif public: typedef typename ntp::lookup<Key1, Params, Keys>::type Key1Type; typedef typename ntp::lookup<Key2, Params, Keys>::type Key2Type; typedef typename ntp::lookup<Key3, Params, Keys>::type Key3Type; enum { value1 = Key1Type::value, value2 = Key2Type::value, value3 = Key3Type::value, }; tester(void) { std::cout << "This: " << libcwd::type_info_of<This>().demangled_name() << std::endl; std::cout << "Value1: " << value1 << std::endl; std::cout << "Value2: " << value2 << std::endl; std::cout << "Value3: " << value3 << std::endl << std::endl; }; }; int main(void) { // NTP semantics: // - For every param_ or param_c argument, bind the specified key // - For every use_default<Key>, explicitly use the default for Key // - For every other parameter (including use_default<>), match // it up with keys not otherwise specified and replace // use_default<> with the appropriate default value // - Implicitly use defaults for any remaining unmatched keys // Use defaults for all typedef tester<> empty; // Binds Key1 typedef tester<boost::mpl::int_<7> > non1; // Binds Key1, Key2 typedef tester< boost::mpl::int_<7>, boost::mpl::int_<8> > non12; // Binds Key1, Key2, Key3 typedef tester< boost::mpl::int_<7>, boost::mpl::int_<8>, boost::mpl::int_<9> > non123; // Binds Key1 typedef tester<ntp::param_c<Key1, long, 4> > key1; // Binds Key1, Key2 typedef tester< ntp::param_c<Key1, long, 4>, boost::mpl::int_<8> > key1non2def3; // Binds Key1, Key2 typedef tester< boost::mpl::int_<8>, ntp::use_default<>, ntp::param_c<Key1, long, 4> > key1non2def3_2; // Binds Key1, Key3 typedef tester< ntp::param_c<Key1, long, 4>, ntp::use_default<Key2>, boost::mpl::int_<9> > key1def2non3; // Binds Key1, Key2 typedef tester< ntp::param_c<Key1, long, 4>, ntp::param_c<Key2, long, 5> > key12; // Binds Key1, Key3 typedef tester< ntp::param_c<Key1, long, 4>, ntp::param_c<Key3, long, 6> > key13; // Binds Key1, Key2, Key3 typedef tester< ntp::param_c<Key1, long, 4>, ntp::param_c<Key2, long, 5>, ntp::param_c<Key3, long, 6> > key123; // Binds Key1, Key2, Key3 typedef tester< ntp::param_c<Key1, long, 4>, ntp::param_c<Key3, long, 6>, ntp::param_c<Key2, long, 5> > key132; empty print_empty; non1 print_non1; non12 print_non12; non123 print_non123; key1 print_key1; key1non2def3 print_key1non2def3; key1non2def3_2 print_key1non2def3_2; key1def2non3 print_key1def2non3; key12 print_key12; key13 print_key13; key123 print_key123; key132 print_key132; return(0); } -------------------------------------- Here's the output: -------------------------------------- This: tester<ntp::default_tag, ntp::default_tag, ntp::default_tag> Value1: 1 Value2: 2 Value3: 3 This: tester<mpl_::int_<7>, ntp::default_tag, ntp::default_tag> Value1: 7 Value2: 2 Value3: 3 This: tester<mpl_::int_<7>, mpl_::int_<8>, ntp::default_tag> Value1: 7 Value2: 8 Value3: 3 This: tester<mpl_::int_<7>, mpl_::int_<8>, mpl_::int_<9> > Value1: 7 Value2: 8 Value3: 9 This: tester<ntp::param_c<Key1, long, (long)4>, ntp::default_tag, ntp::default_tag> Value1: 4 Value2: 2 Value3: 3 This: tester<ntp::param_c<Key1, long, (long)4>, mpl_::int_<8>, ntp::default_tag>Value1: 4 Value2: 8 Value3: 3 This: tester<mpl_::int_<8>, ntp::use_default<mpl_::void_>, ntp::param_c<Key1, long, (long)4> > Value1: 4 Value2: 8 Value3: 3 This: tester<ntp::param_c<Key1, long, (long)4>, ntp::use_default<Key2>, mpl_::int_<9> > Value1: 4 Value2: 2 Value3: 9 This: tester<ntp::param_c<Key1, long, (long)4>, ntp::param_c<Key2, long, (long)5>, ntp::default_tag> Value1: 4 Value2: 5 Value3: 3 This: tester<ntp::param_c<Key1, long, (long)4>, ntp::param_c<Key3, long, (long)6>, ntp::default_tag> Value1: 4 Value2: 2 Value3: 6 This: tester<ntp::param_c<Key1, long, (long)4>, ntp::param_c<Key2, long, (long)5>, ntp::param_c<Key3, long, (long)6> > Value1: 4 Value2: 5 Value3: 6 This: tester<ntp::param_c<Key1, long, (long)4>, ntp::param_c<Key3, long, (long)6>, ntp::param_c<Key2, long, (long)5> > Value1: 4 Value2: 5 Value3: 6

David Greene wrote:
David Abrahams wrote:
There has already been a released named_template_params.hpp in boost/detail "forever". http://www.boost.org/boost/detail/named_template_params.hpp
I know this used to be used by the old iterator_adaptors. I can't quite remember what the interface to named_template_params was and it's a little difficult for me to envision given just the header file. Got an example laying around somewhere?
Something like: my_template<foo_is<int>, bar_is<long**> > IOW, iterator_adaptor<value_type_is<char>, reference_is<char&> >
IMO named template parameters are unweildy in C++. I prefer "unnamed template parameters" like those described in http://www.boost.org/libs/python/doc/v2/class.html
"Boost.Python determines the role of the argument from its type."
So does that mean that this idiom can only be used when each argument is of a distinct type?
Strictly speaking, no. You're okay as long as it is possible to know, when you are passed some type X twice, which two "logical" template parameters are intended.
I realize that this can be made to happen by wrapping each argument in a unique class, but isn't that exactly what named template parameters is?
It really depends on the interface of the outer template. If it's truly general and there's no restriction on the types of its arguments or their relationships, then you do need to resort to xxxx_is<...> style wrappers everywhere. Otherwise, you may be able to avoid those wrappers in some or all places.
The use of what I've got working now is shown below. Things I don't like about this include:
- Necessity of passing key_info<> to lookup<>. I tried to do this through default template args but I couldn't come up with a working solution.
- The separation of parameter declaration and default value definition.
- Packaging up all parameters into an MPL sequence. It's not so bad, though.
What's not to like about that?
Would anyone find this useful? Obviously it will need some work. I'd like to clean up the syntax some if possible.
The reason we dropped the named template parameter interface to iterator adaptors was that nobody was using it. The default computation was so complicated that most iterator authors wanted to specify all the parameters explicitly. So before we make NTP into a real library I'd like to see it pass some real-world usability tests. If there was at least anecdotal evidence that people were using and liking it, I'd be satisfied. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
I know this used to be used by the old iterator_adaptors. I can't quite remember what the interface to named_template_params was and it's a little difficult for me to envision given just the header file. Got an example laying around somewhere?
Something like:
my_template<foo_is<int>, bar_is<long**> >
IOW,
iterator_adaptor<value_type_is<char>, reference_is<char&> >
I remember that part but I recall that there is some additional setup for the user to do (defining foo_is, perhaps?). By "user" I guess I mean class template developer.
"Boost.Python determines the role of the argument from its type."
So does that mean that this idiom can only be used when each argument is of a distinct type?
Strictly speaking, no. You're okay as long as it is possible to know, when you are passed some type X twice, which two "logical" template parameters are intended.
Can you give me an example of how that can be done? From context provided by the other template parameters? I'm just trying to grasp how this works and understand how it compares to NTP, why NTP might not be the best way to go, etc.
I realize that this can be made to happen by wrapping each argument in a unique class, but isn't that exactly what named template parameters is?
It really depends on the interface of the outer template. If it's truly general and there's no restriction on the types of its arguments or their relationships, then you do need to resort to xxxx_is<...> style wrappers everywhere. Otherwise, you may be able to avoid those wrappers in some or all places.
Ok, maybe I'm starting to grasp it. In my particular case, all my template parameters are integers so I need a way to identify which integer value is supposed to go where. That's why I developed the named template parameters framework and it's not coincidental that my example passed integer arguments around. ;)
The use of what I've got working now is shown below. Things I don't like about this include:
- Necessity of passing key_info<> to lookup<>. I tried to do this through default template args but I couldn't come up with a working solution.
- The separation of parameter declaration and default value definition.
- Packaging up all parameters into an MPL sequence. It's not so bad, though.
What's not to like about that?
The packaging? It's just an extra step. Like I said, it's not a big deal. I'm more disappointed that I couldn't hook into the C++ default template arguments mechanism to pass NTP defaults.
Would anyone find this useful? Obviously it will need some work. I'd like to clean up the syntax some if possible.
The reason we dropped the named template parameter interface to iterator adaptors was that nobody was using it. The default computation was so complicated that most iterator authors wanted to specify all the parameters explicitly. So before we make NTP into a real library I'd like to see it pass some real-world usability tests. If there was at least anecdotal evidence that people were using and liking it, I'd be satisfied.
Actually, I did some work with iterator_adaptors about a year ago and I found the named template parameters to be useful. I specified everything but I didn't want to care what order I did it in and the value_type_is<>, etc. gave me visual cues as a developer what each argument is used for. I was sad to see this capability gone in the new library. I tried to take the idea of NTP from iterator_adaptors and make it more generic by changing value_is<>, etc. to simple struct tag classes that can be wrapped with a default value into default_<> or default_c<> parameters. Users would then pass param<Key, Value> pairs as the template arguments. So the difference in usage is: Key_is<Value> vs. param<Key, Value> The nice thing about the latter is the client class template using NTP doesn't have to define searches for Key_is. It just passes the set of keys to ntp::key_info<> and does an ntp::lookup<Key, Params, key_info<> >. I don't recall how the searching was done with named_template_params.hpp. It may just be a matter of syntax for all I know. If I have time, I'll grab a copy of the old iterator_adaptors library and do some comparisons. I'd think that the same arguments that motivated the named function parameters library would motivate a named template parameters library. I appreciate your insight and feedback on this. -Dave

David Greene wrote:
David Abrahams wrote:
I know this used to be used by the old iterator_adaptors. I can't quite remember what the interface to named_template_params was and it's a little difficult for me to envision given just the header file. Got an example laying around somewhere?
Something like:
my_template<foo_is<int>, bar_is<long**> >
IOW,
iterator_adaptor<value_type_is<char>, reference_is<char&> >
I remember that part but I recall that there is some additional setup for the user to do (defining foo_is, perhaps?). By "user" I guess I mean class template developer.
Yes. But I don't remember what was required. You can always look back through the CVS history for boost/iterator_adaptor.hpp
"Boost.Python determines the role of the argument from its type."
So does that mean that this idiom can only be used when each argument is of a distinct type?
Strictly speaking, no. You're okay as long as it is possible to know, when you are passed some type X twice, which two "logical" template parameters are intended.
Can you give me an example of how that can be done? From context provided by the other template parameters?
That, and the requirements of the template. For example, if you have a template foo that takes up to 3 logical parameters. Parameter A, if supplied, must be a class type. Parameter B, if supplied, must be the same as or derived from A. It defaults to A. Parameter C, if supplied, must be a pointer or smart pointer to B if I write foo<bar,bar>, you can tell that both A and B are bar, so it doesn't really matter which one is which ;-)
I'm just trying to grasp how this works and understand how it compares to NTP, why NTP might not be the best way to go, etc.
I realize that this can be made to happen by wrapping each argument in a unique class, but isn't that exactly what named template parameters is?
It really depends on the interface of the outer template. If it's truly general and there's no restriction on the types of its arguments or their relationships, then you do need to resort to xxxx_is<...> style wrappers everywhere. Otherwise, you may be able to avoid those wrappers in some or all places.
Ok, maybe I'm starting to grasp it. In my particular case, all my template parameters are integers so I need a way to identify which integer value is supposed to go where. That's why I developed the named template parameters framework and it's not coincidental that my example passed integer arguments around. ;)
Okay. I guess there's no restriction on the relationships among those integers?
Would anyone find this useful? Obviously it will need some work. I'd like to clean up the syntax some if possible.
The reason we dropped the named template parameter interface to iterator adaptors was that nobody was using it. The default computation was so complicated that most iterator authors wanted to specify all the parameters explicitly. So before we make NTP into a real library I'd like to see it pass some real-world usability tests. If there was at least anecdotal evidence that people were using and liking it, I'd be satisfied.
Actually, I did some work with iterator_adaptors about a year ago and I found the named template parameters to be useful. I specified everything but I didn't want to care what order I did it in and the value_type_is<>, etc. gave me visual cues as a developer what each argument is used for. I was sad to see this capability gone in the new library.
Hm, interesting.
I tried to take the idea of NTP from iterator_adaptors and make it more generic by changing value_is<>, etc. to simple struct tag classes that can be wrapped with a default value into default_<> or default_c<> parameters. Users would then pass param<Key, Value> pairs as the template arguments. So the difference in usage is:
Key_is<Value>
vs.
param<Key, Value>
The nice thing about the latter is the client class template using NTP doesn't have to define searches for Key_is.
The bad thing about it is that it's more verbose for the ultimate user. The ultimate user is more important than the designer of the client class template.
It just passes the set of keys to ntp::key_info<> and does an ntp::lookup<Key, Params, key_info<> >.
I don't recall how the searching was done with named_template_params.hpp. It may just be a matter of syntax for all I know. If I have time, I'll grab a copy of the old iterator_adaptors library and do some comparisons.
I'd think that the same arguments that motivated the named function parameters library would motivate a named template parameters library.
Unless the syntax turned out to be too unwieldy.
I appreciate your insight and feedback on this.
One last thing: I bet the named function parameters library and the named template parameters library could be made to share most of the same core machinery. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

David Abrahams wrote:
Okay. I guess there's no restriction on the relationships among those integers?
Correct. They are independent dimensions in an engineering experiment framework I'm developing.
The bad thing about it is that it's more verbose for the ultimate user.
Yes, you are right.
The ultimate user is more important than the designer of the client class template.
True. It's something I do want to revisit.
I'd think that the same arguments that motivated the named function parameters library would motivate a named template parameters library.
Unless the syntax turned out to be too unwieldy.
Right. Which is where the feedback part comes in. :)
One last thing: I bet the named function parameters library and the named template parameters library could be made to share most of the same core machinery.
Possibly. Any development notes available (besides list archives, that is)? -Dave

David A. Greene wrote:
One last thing: I bet the named function parameters library and the named template parameters library could be made to share most of the same core machinery.
Possibly. Any development notes available (besides list archives, that is)?
No. In fact, Daniel made most of the last round of major changes, so I have to review the code carefully to understand it. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com

The reason we dropped the named template parameter interface to iterator adaptors was that nobody was using it. The default computation was so complicated that most iterator authors wanted to specify all the parameters explicitly. So before we make NTP into a real library I'd like to see it pass some real-world usability tests. If there was at least anecdotal evidence that people were using and liking it, I'd be satisfied.
I remember NTP were really usefull in multi-policy based solutions. (for example policy based smart pointer) Gennadiy

Gennadiy Rozental wrote:
The reason we dropped the named template parameter interface to iterator adaptors was that nobody was using it. The default computation was so complicated that most iterator authors wanted to specify all the parameters explicitly. So before we make NTP into a real library I'd like to see it pass some real-world usability tests. If there was at least anecdotal evidence that people were using and liking it, I'd be satisfied.
I remember NTP were really usefull in multi-policy based solutions. (for example policy based smart pointer)
I think it is useful in single-policy based solutions as well with "variable" number of template parameters. For instance you could imagine tuple having an assignment policy. Eugene

I think it is useful in single-policy based solutions as well with "variable" number of template parameters. For instance you could imagine tuple having an assignment policy.
Eugene
Key thing here is *"variable" number of template parameters*. Whether they are policies or anything else doesn't matter. Gennadiy
participants (5)
-
David A. Greene
-
David Abrahams
-
David Greene
-
E. Gladyshev
-
Gennadiy Rozental