</pre>
\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<void (std::ostream &, std::string const &)>(
+ 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
+ <pre>
+ server:/$ test8 ok
+ ok
+ ok
+ ok
+ ok
+ server:/$ help test8
+ Usage:
+ test8 arg11:string
+ server:/$
+ </pre>
+ \endhtmlonly
+
+
\subsection console_attr_summary Attribute summary
Here a summary of the most common attributes
///////////////////////////////////////////////////////////////////////////
// namespace members
-namespace {
+namespace senf {
+namespace console {
+namespace detail {
+
+ struct ParsedCommandAddNodeAccess
+ {
+ template <class Attributor, class Node>
+ static Attributor attributor(Node & node)
+ { return Attributor(node); }
+ };
// What is THIS about ??
// 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 <class Traits, bool ignoreOneArg, unsigned arity=Traits::arity>
+ template <class Traits,
+ bool ignoreOneArg=! Traits::has_ostream_arg,
+ unsigned arity=Traits::traits::arity>
struct CreateParsedCommandOverload
{};
template <class Traits, unsigned arity>
struct CreateParsedCommandOverload<Traits, false, arity>
{
- typedef Traits traits;
+ typedef typename Traits::traits traits;
template <class Function>
static typename senf::console::ParsedCommandOverload<traits>::ptr create(Function fn)
4))
# include BOOST_PP_ITERATE()
-}
+ template <class Signature, class Fn>
+ typename senf::console::detail::ParsedCommandTraits<Signature>::Attributor
+ addOverloadedCommandNode(senf::console::DirectoryNode & node, std::string const & name, Fn fn)
+ {
+ senf::console::OverloadedCommandNode & cmdNode (
+ node.hasChild(name)
+ ? dynamic_cast<senf::console::OverloadedCommandNode &>(node(name))
+ : node.add(name, senf::console::OverloadedCommandNode::create()) );
+
+ typedef senf::console::detail::ParsedCommandTraits<Signature> CmdTraits;
+ typedef senf::console::ParsedCommandOverload<typename CmdTraits::traits> Overload;
+ typedef senf::console::ParsedArgumentAttributor<Overload> Attributor;
+
+ return senf::console::detail::ParsedCommandAddNodeAccess::attributor<Attributor>(
+ cmdNode.add( CreateParsedCommandOverload<CmdTraits>::create(fn) ) );
+ }
+
+}}}
template <class Function>
-prefix_ senf::console::ParsedArgumentAttributor<
- senf::console::ParsedCommandOverload<
- typename senf::console::detail::ParsedCommandTraits<Function>::traits> >
+typename senf::console::detail::ParsedCommandTraits<Function>::Attributor
senf::console::senf_console_add_node(DirectoryNode & node, std::string const & name,
Function fn, int)
{
- OverloadedCommandNode & cmdNode (
- node.hasChild(name)
- ? dynamic_cast<OverloadedCommandNode &>(node(name))
- : node.add(name, OverloadedCommandNode::create()) );
-
- typedef detail::ParsedCommandTraits<Function> CmdTraits;
- typedef ParsedCommandOverload<typename CmdTraits::traits> Overload;
- typedef ParsedArgumentAttributor<Overload> Attributor;
-
- return Attributor(
- cmdNode.add( CreateParsedCommandOverload<
- typename CmdTraits::traits, ! CmdTraits::has_ostream_arg>::create(fn) ) );
+ return senf::console::detail::addOverloadedCommandNode<Function>(node, name, fn);
+}
+
+template <class Signature>
+typename senf::console::detail::ParsedCommandTraits<Signature>::Attributor
+senf::console::senf_console_add_node(DirectoryNode & node, std::string const & name,
+ boost::function<Signature> fn, int)
+{
+ return senf::console::detail::addOverloadedCommandNode<Signature>(node, name, fn);
}
template <class Owner, class Function>
-prefix_ senf::console::ParsedArgumentAttributor<
- senf::console::ParsedCommandOverload<
- typename senf::console::detail::ParsedCommandTraits<Function>::traits> >
-senf::console::
-senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
- Function fn, int,
- typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_member>::type *)
+typename senf::console::detail::ParsedCommandTraits<Function>::Attributor
+senf::console::senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
+ Function fn, int,
+ typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_member>::type *)
{
- OverloadedCommandNode & cmdNode (
- node.hasChild(name)
- ? dynamic_cast<OverloadedCommandNode &>(node(name))
- : node.add(name, OverloadedCommandNode::create()) );
-
- typedef detail::ParsedCommandTraits<Function> CmdTraits;
- typedef ParsedCommandOverload<typename CmdTraits::traits> Overload;
- typedef ParsedArgumentAttributor<Overload> Attributor;
-
- return Attributor(
- cmdNode.add( CreateParsedCommandOverload<
- typename CmdTraits::traits, ! CmdTraits::has_ostream_arg>::create(
- senf::membind(fn,&owner)) ) );
+ return senf::console::detail::addOverloadedCommandNode<Function>(
+ node, name, senf::membind(fn,&owner));
}
///////////////////////////////cti.e///////////////////////////////////////
\todo Implement automatic binding of member functions for parser and formatter
*/
- template <class FunctionTraits, class ReturnType=typename FunctionTraits::result_type,
- unsigned arity=FunctionTraits::arity>
+ template <class FunctionTraits, class ReturnType, unsigned arity>
class ParsedCommandOverload : public ParsedCommandOverloadBase
{
public:
assigned in the following way:
<table class="senf fixedwidth">
<tr>
- <td><tt>command 1 2</tt></td>
- <td>SyntaxErrorException: invalid number of
+ <td style="whitespace:no-wrap"><tt>command 1 2</tt></td>
+ <td colspan="5">SyntaxErrorException: invalid number of
arguments</td>
</tr>
<tr>
- <td><tt>command 1 2 3</tt></td>
- <td>\a a = 1, \n
- \a b = \e default, \n
- \a c = 2, \n
- \a d = \e default, \n
- \a e = 3</td>
+ <td style="white-space:nowrap"><tt>command 1 2 3</tt></td>
+ <td style="width:6em">\a a = 1</td><td style="width:6em">\a b = \e default</td><td style="width:6em">\a c = 2</td><td style="width:6em">\a d = \e default</td><td style="width:6em">\a e = 3</td>
</tr>
<tr>
- <td><tt>command 1 2 3 4</tt></td>
- <td>\a a = 1, \n
- \a b = 2, \n
- \a c = 3, \n
- \a d = \e default, \n
- \a e = 4</td>
+ <td style="white-space:nowrap"><tt>command 1 2 3 4</tt></td>
+ <td>\a a = 1</td><td>\a b = 2</td><td>\a c = 3</td><td>\a d = \e default</td><td>\a e = 4</td>
</tr>
<tr>
- <td><tt>command 1 2 3 4 5</tt></td>
- <td>\a a = 1, \n
- \a b = 2, \n
- \a c = 3, \n
- \a d = 4, \n
- \a e = 5</td>
+ <td style="white-space:nowrap"><tt>command 1 2 3 4 5</tt></td>
+ <td>\a a = 1</td><td>\a b = 2</td><td>\a c = 3</td><td>\a d = 4</td><td>\a e = 5</td>
</tr>
<tr>
- <td><tt>command 1 2 3 4 5 6</tt></td>
- <td>SyntaxErrorException: invalid number of
+ <td style="white-space:nowrap"><tt>command 1 2 3 4 5 6</tt></td>
+ <td colspan="5">SyntaxErrorException: invalid number of
arguments</td>
</tr>
</table>
- 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
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);
\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<Overload, index, flag> >
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
template <class O, unsigned i, bool f>
friend class ParsedArgumentAttributor;
-#ifndef DOXYGEN
-
- template <class Function>
- friend ParsedArgumentAttributor<
- ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
- senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
-
- template <class Owner, class Function>
- friend ParsedArgumentAttributor<
- ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
- senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
- Function fn, int,
- typename boost::enable_if_c<
- detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
-
-#endif
+ friend class detail::ParsedCommandAddNodeAccess;
};
#ifndef DOXYGEN
template <class O, unsigned i, bool f>
friend class ParsedArgumentAttributor;
-
- template <class Function>
- friend ParsedArgumentAttributor<
- ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
- senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
-
- template <class Owner, class Function>
- friend ParsedArgumentAttributor<
- ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
- senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
- Function fn, int,
- typename boost::enable_if_c<
- detail::ParsedCommandTraits<Function>::is_member>::type * = 0);
+
+ friend class detail::ParsedCommandAddNodeAccess;
};
template <class Function>
- ParsedArgumentAttributor<
- ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
+ typename detail::ParsedCommandTraits<Function>::Attributor
senf_console_add_node(DirectoryNode & node, std::string const & name, Function fn, int);
+ template <class Signature>
+ typename detail::ParsedCommandTraits<Signature>::Attributor
+ senf_console_add_node(DirectoryNode & node, std::string const & name, boost::function<Signature> fn, int);
+
template <class Owner, class Function>
- ParsedArgumentAttributor<
- ParsedCommandOverload<typename detail::ParsedCommandTraits<Function>::traits> >
+ typename detail::ParsedCommandTraits<Function>::Attributor
senf_console_add_node(DirectoryNode & node, Owner & owner, std::string const & name,
Function fn, int,
typename boost::enable_if_c<
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
struct ParsedCommandTraits
{};
- template <class Function>
- struct ParsedCommandTraits<Function, true>
+ template <class Fn>
+ struct ParsedCommandTraits<Fn, true>
{
- typedef Function base_type;
+ typedef Fn base_type;
typedef typename senf::remove_any_pointer<base_type>::type function_type;
typedef boost::function_traits<function_type> base_traits;
typedef typename FirstArgType<base_traits>::type first_arg_type;
static const bool is_member = boost::is_member_pointer<base_type>::value;
typedef typename senf::member_class<base_type>::type class_type;
+
+ typedef ParsedCommandOverload<traits> Overload;
+ typedef ParsedArgumentAttributor<Overload> Attributor;
};
+ struct ParsedCommandAddNodeAccess;
+
#endif
}}}
template <class Traits>
struct CreateParsedCommandOverload<Traits, true, BOOST_PP_ITERATION()>
{
- typedef Traits traits;
+ typedef typename Traits::traits traits;
template <class Function>
static typename senf::console::ParsedCommandOverload<traits>::ptr create(Function fn)
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"; }
};
{
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<float()>(&cb2))
.formatter( &testFormatter );
BOOST_CHECK_NO_THROW(
parser.parse("test/cb7",