From: g0dil Date: Wed, 16 Apr 2008 08:57:06 +0000 (+0000) Subject: Console; Support non-function-pointer parsed commands via boost::function X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=6bf246297d5a9b158b3c179e15d181df6e85a9bd;p=senf.git Console; Support non-function-pointer parsed commands via boost::function git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@814 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Console/Mainpage.dox b/Console/Mainpage.dox index 6929f25..d1de4fe 100644 --- a/Console/Mainpage.dox +++ b/Console/Mainpage.dox @@ -512,6 +512,38 @@ \endhtmlonly + + \subsection console_boostfn Adding non-function-pointer callable objects + + It is possible to add other callable objects besides function (and member-function) + pointers. However, since it is not possible to automatically deduce the argument and return + types in this case, the callables have to be wrapped in a \c boost::function object: + + \code + senf::console::root() + .add("test8", + boost::function( + boost::bind(&fun3, _1, 4u, _2))); + \endcode + + This works with any callable object where argument types cannot be deduced automatically: + Boost.Bind expressions, Boost.Lambda expressions, functors and so on. + + \htmlonly +
+    server:/$ test8 ok
+    ok
+    ok
+    ok
+    ok
+    server:/$ help test8
+    Usage:
+        test8 arg11:string
+    server:/$
+    
+ \endhtmlonly + + \subsection console_attr_summary Attribute summary Here a summary of the most common attributes diff --git a/Console/ParsedCommand.cti b/Console/ParsedCommand.cti index 029fa2d..1aa2020 100644 --- a/Console/ParsedCommand.cti +++ b/Console/ParsedCommand.cti @@ -331,7 +331,16 @@ ParsedArgumentAttributor(Overload & overload) /////////////////////////////////////////////////////////////////////////// // namespace members -namespace { +namespace senf { +namespace console { +namespace detail { + + struct ParsedCommandAddNodeAccess + { + template + static Attributor attributor(Node & node) + { return Attributor(node); } + }; // What is THIS about ?? @@ -347,14 +356,16 @@ namespace { // If however, it does NOT take an std::ostream first argument, 'ignoreOneArg' will be true and // the create member will use boost::bind to DROP the first argument. - template + template struct CreateParsedCommandOverload {}; template struct CreateParsedCommandOverload { - typedef Traits traits; + typedef typename Traits::traits traits; template static typename senf::console::ParsedCommandOverload::ptr create(Function fn) @@ -366,51 +377,49 @@ namespace { 4)) # include BOOST_PP_ITERATE() -} + template + typename senf::console::detail::ParsedCommandTraits::Attributor + addOverloadedCommandNode(senf::console::DirectoryNode & node, std::string const & name, Fn fn) + { + senf::console::OverloadedCommandNode & cmdNode ( + node.hasChild(name) + ? dynamic_cast(node(name)) + : node.add(name, senf::console::OverloadedCommandNode::create()) ); + + typedef senf::console::detail::ParsedCommandTraits CmdTraits; + typedef senf::console::ParsedCommandOverload Overload; + typedef senf::console::ParsedArgumentAttributor Attributor; + + return senf::console::detail::ParsedCommandAddNodeAccess::attributor( + cmdNode.add( CreateParsedCommandOverload::create(fn) ) ); + } + +}}} template -prefix_ senf::console::ParsedArgumentAttributor< - senf::console::ParsedCommandOverload< - typename senf::console::detail::ParsedCommandTraits::traits> > +typename senf::console::detail::ParsedCommandTraits::Attributor senf::console::senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int) { - OverloadedCommandNode & cmdNode ( - node.hasChild(name) - ? dynamic_cast(node(name)) - : node.add(name, OverloadedCommandNode::create()) ); - - typedef detail::ParsedCommandTraits CmdTraits; - typedef ParsedCommandOverload Overload; - typedef ParsedArgumentAttributor Attributor; - - return Attributor( - cmdNode.add( CreateParsedCommandOverload< - typename CmdTraits::traits, ! CmdTraits::has_ostream_arg>::create(fn) ) ); + return senf::console::detail::addOverloadedCommandNode(node, name, fn); +} + +template +typename senf::console::detail::ParsedCommandTraits::Attributor +senf::console::senf_console_add_node(DirectoryNode & node, std::string const & name, + boost::function fn, int) +{ + return senf::console::detail::addOverloadedCommandNode(node, name, fn); } template -prefix_ senf::console::ParsedArgumentAttributor< - senf::console::ParsedCommandOverload< - typename senf::console::detail::ParsedCommandTraits::traits> > -senf::console:: -senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, - Function fn, int, - typename boost::enable_if_c::is_member>::type *) +typename senf::console::detail::ParsedCommandTraits::Attributor +senf::console::senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, + Function fn, int, + typename boost::enable_if_c::is_member>::type *) { - OverloadedCommandNode & cmdNode ( - node.hasChild(name) - ? dynamic_cast(node(name)) - : node.add(name, OverloadedCommandNode::create()) ); - - typedef detail::ParsedCommandTraits CmdTraits; - typedef ParsedCommandOverload Overload; - typedef ParsedArgumentAttributor Attributor; - - return Attributor( - cmdNode.add( CreateParsedCommandOverload< - typename CmdTraits::traits, ! CmdTraits::has_ostream_arg>::create( - senf::membind(fn,&owner)) ) ); + return senf::console::detail::addOverloadedCommandNode( + node, name, senf::membind(fn,&owner)); } ///////////////////////////////cti.e/////////////////////////////////////// diff --git a/Console/ParsedCommand.hh b/Console/ParsedCommand.hh index a4ef298..ba32137 100644 --- a/Console/ParsedCommand.hh +++ b/Console/ParsedCommand.hh @@ -171,8 +171,7 @@ namespace console { \todo Implement automatic binding of member functions for parser and formatter */ - template + template class ParsedCommandOverload : public ParsedCommandOverloadBase { public: @@ -329,42 +328,32 @@ namespace console { assigned in the following way: - - + - - + + - - + + - - + + - - +
command 1 2SyntaxErrorException: invalid number of + command 1 2SyntaxErrorException: invalid number of arguments
command 1 2 3\a a = 1, \n - \a b = \e default, \n - \a c = 2, \n - \a d = \e default, \n - \a e = 3command 1 2 3\a a = 1\a b = \e default\a c = 2\a d = \e default\a e = 3
command 1 2 3 4\a a = 1, \n - \a b = 2, \n - \a c = 3, \n - \a d = \e default, \n - \a e = 4command 1 2 3 4\a a = 1\a b = 2\a c = 3\a d = \e default\a e = 4
command 1 2 3 4 5\a a = 1, \n - \a b = 2, \n - \a c = 3, \n - \a d = 4, \n - \a e = 5command 1 2 3 4 5\a a = 1\a b = 2\a c = 3\a d = 4\a e = 5
command 1 2 3 4 5 6SyntaxErrorException: invalid number of + command 1 2 3 4 5 6SyntaxErrorException: invalid number of arguments
- So, if you assign default values as you are used to - they will work like in C++ and most other languages */ + So, if you use default values as you are used to, + assigning default values to consecutive trailing + arguments, they work like they do in C++ and most other + languages */ BOOST_PARAMETER_KEYWORD(type, type_name) ///< Type name of this arguments type /**< By default, the type of an argument is extracted from the C++ type name by taking the last component of the @@ -413,7 +402,18 @@ namespace console { public: Self doc(std::string const & doc) const; ///< Set documentation for all overloads Self overloadDoc(std::string const & doc) const; ///< Set overload specific documentation - Self formatter(typename Overload::Formatter f) const; ///< Set return value formatter + Self formatter(typename Overload::Formatter formatter) const; + ///< Set return value formatter + /**< This member is only available, if the \a ReturnType of + the installed callback is not \c void. + + If \a ReturnType is not \c void, the \a formatter must + be a callable with a signature compatible with + \code + void formatter(ReturnType const & value, std::ostream & os); + \endcode + The \a formatter takes the return value of the call \a + value and writes it properly formated to \a os. */ protected: ParsedArgumentAttributorBase(Overload & overload, unsigned index); @@ -449,9 +449,7 @@ namespace console { \see \ref console_autoparse */ - template < class Overload, - unsigned index=0, - bool flag=(index < unsigned(Overload::traits::arity)) > + template < class Overload, unsigned index, bool flag> class ParsedArgumentAttributor : public ParsedArgumentAttributorBase< Overload, ParsedArgumentAttributor > @@ -490,7 +488,8 @@ namespace console { Each call to arg() will increment the argument index and advance to the next argument. This member is only - present, if there is an argument at the current. */ + present, if there is an argument at the current + index. */ #ifndef DOXYVEN @@ -544,22 +543,7 @@ namespace console { template friend class ParsedArgumentAttributor; -#ifndef DOXYGEN - - template - friend ParsedArgumentAttributor< - ParsedCommandOverload::traits> > - senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); - - template - friend ParsedArgumentAttributor< - ParsedCommandOverload::traits> > - senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, - Function fn, int, - typename boost::enable_if_c< - detail::ParsedCommandTraits::is_member>::type * = 0); - -#endif + friend class detail::ParsedCommandAddNodeAccess; }; #ifndef DOXYGEN @@ -578,29 +562,20 @@ namespace console { template friend class ParsedArgumentAttributor; - - template - friend ParsedArgumentAttributor< - ParsedCommandOverload::traits> > - senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); - - template - friend ParsedArgumentAttributor< - ParsedCommandOverload::traits> > - senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, - Function fn, int, - typename boost::enable_if_c< - detail::ParsedCommandTraits::is_member>::type * = 0); + + friend class detail::ParsedCommandAddNodeAccess; }; template - ParsedArgumentAttributor< - ParsedCommandOverload::traits> > + typename detail::ParsedCommandTraits::Attributor senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int); + template + typename detail::ParsedCommandTraits::Attributor + senf_console_add_node(DirectoryNode & node, std::string const & name, boost::function fn, int); + template - ParsedArgumentAttributor< - ParsedCommandOverload::traits> > + typename detail::ParsedCommandTraits::Attributor senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name, Function fn, int, typename boost::enable_if_c< diff --git a/Console/ParsedCommand.ih b/Console/ParsedCommand.ih index d4a89f8..c2d887b 100644 --- a/Console/ParsedCommand.ih +++ b/Console/ParsedCommand.ih @@ -35,6 +35,17 @@ namespace senf { namespace console { + + template < class FunctionTraits, + class ReturnType=typename FunctionTraits::result_type, + unsigned arity=FunctionTraits::arity > + class ParsedCommandOverload; + + template < class Overload, + unsigned index=0, + bool flag=(index < unsigned(Overload::traits::arity)) > + class ParsedArgumentAttributor; + namespace detail { #ifndef DOXYGEN @@ -90,10 +101,10 @@ namespace detail { struct ParsedCommandTraits {}; - template - struct ParsedCommandTraits + template + struct ParsedCommandTraits { - typedef Function base_type; + typedef Fn base_type; typedef typename senf::remove_any_pointer::type function_type; typedef boost::function_traits base_traits; typedef typename FirstArgType::type first_arg_type; @@ -111,8 +122,13 @@ namespace detail { static const bool is_member = boost::is_member_pointer::value; typedef typename senf::member_class::type class_type; + + typedef ParsedCommandOverload Overload; + typedef ParsedArgumentAttributor Attributor; }; + struct ParsedCommandAddNodeAccess; + #endif }}} diff --git a/Console/ParsedCommand.mpp b/Console/ParsedCommand.mpp index bfa3ef3..ede6974 100644 --- a/Console/ParsedCommand.mpp +++ b/Console/ParsedCommand.mpp @@ -259,7 +259,7 @@ v_execute(std::ostream & os, ParseCommandInfo const & command) template struct CreateParsedCommandOverload { - typedef Traits traits; + typedef typename Traits::traits traits; template static typename senf::console::ParsedCommandOverload::ptr create(Function fn) diff --git a/Console/ParsedCommand.test.cc b/Console/ParsedCommand.test.cc index a9e47a4..223a3e3 100644 --- a/Console/ParsedCommand.test.cc +++ b/Console/ParsedCommand.test.cc @@ -50,11 +50,8 @@ namespace { struct TestParser { - typedef senf::console::ParseCommandInfo::TokensRange const & first_argument_type; - typedef std::string & second_argument_type; - typedef void result_type; - - result_type operator()(first_argument_type, second_argument_type out) const + void operator()(senf::console::ParseCommandInfo::TokensRange const &, + std::string & out) const { out = "true"; } }; @@ -144,7 +141,9 @@ BOOST_AUTO_UNIT_TEST(parsedCommand) { std::stringstream ss; - dir.add("cb7", &cb2) + // This tests adding boost::function objects and at the same time validates, that + // compatible types also work + dir.add("cb7", boost::function(&cb2)) .formatter( &testFormatter ); BOOST_CHECK_NO_THROW( parser.parse("test/cb7",