753bd836a0bfa3405a38316ce64e305db60778cb
[senf.git] / senf / Utils / Console / ParsedCommand.hh
1 // $Id$
2 //
3 // Copyright (C) 2008
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief ParsedCommand public header */
25
26 #ifndef HH_SENF_Scheduler_Console_ParsedCommand_
27 #define HH_SENF_Scheduler_Console_ParsedCommand_ 1
28
29 // Custom includes
30
31 #define BOOST_PARAMETER_MAX_ARITY 6
32
33 #include <vector>
34 #include <boost/type_traits/function_traits.hpp>
35 #include <boost/type_traits/is_member_function_pointer.hpp>
36 #include <boost/mpl/if.hpp>
37 #include <boost/utility.hpp>
38 #include <boost/parameter/keyword.hpp>
39 #include <boost/parameter/parameters.hpp>
40 #include <senf/config.hh>
41 #include "OverloadedCommand.hh"
42 #include "Traits.hh"
43 #include <senf/Utils/type_traits.hh>
44
45 #include "ParsedCommand.ih"
46 #include "ParsedCommand.mpp"
47 ///////////////////////////////hh.p////////////////////////////////////////
48
49 namespace senf {
50 namespace console {
51
52     namespace detail { class ArgumentInfoBase; }
53
54     /** \brief CommandOverload implementation with automatic argument parsing
55
56         ParsedCommandOverloadBase implements a CommandOverload implementation supporting automatic
57         parsing of arguments. This is \e not a node, it's a CommandOverload which is then added to
58         an OverloadedCommandNode instance.
59
60         Automatic argument parsing and return value processing consists of several components:
61         \li \ref overload_add Adding overload instances to the tree
62         \li (Advanced) \ref overload_parse
63         \li (Advanced) \ref overload_format
64
65         \section overload_add Adding argument parsing callbacks to the tree
66
67         Adding appropriate callbacks to the tree is very simple: just path a function pointer to
68         DirectoryNode::add() or a member function pointer to ScopedDirectory::add().
69         \code
70         std::string taskStatus(int id);
71
72         senf::console::root().add("taskStatus", &taskStatus);
73         \endcode
74
75         There are quite a number of additional parameters available to be set. These parameters are
76         documented in ParsedArgumentAttributor. Parameters are set by adding them as additional
77         calls after adding the node:
78
79         \code
80         senf::console::root().add("taskStatus", &taskStatus)
81             .doc("Query the current task status")
82             .arg( name = "id",
83                   description = "numeric id of task to check, -1 for the current task."
84                   default_value = -1 );
85         \endcode
86
87         You may also add an additional \c std::ostream & Argument as first argument to the
88         callback. If this argument is present, the stream connected to the console which issued the
89         command will be passed there. This allows writing arbitrary messages to the console.
90
91         Additionally, overloading is supported by registering multiple commands under the same
92         name. So, elaborating on above example:
93         \code
94         std::string taskStatus(int id);
95         std::string taskStatus(std::string const & name);
96
97         senf::console::root()
98             .add("taskStatus", static_cast<std::string (*)(int)>(&taskStatus))
99             .doc("Query the current task status")
100             .overloadDoc("Query status by id")
101             .arg( name = "id",
102                   description = "numeric id of task to check, -1 for the current task."
103                   default_value = -1 );
104         senf::console::root()
105             .add("taskStatus", static_cast<std::string (*)(std::string const &)>(&taskStatus))
106             .overloadDoc("Query status by name")
107             .arg( name = "name",
108                   description = "name of task to check" );
109         \endcode
110
111         We can see here, that taking the address of an overloaded function requires a cast. If you
112         can give unique names to each of the C++ overloads (not the overloads in the console), you
113         should do so to make the unwieldy casts unnecessary.
114
115         \section overload_parse Custom parameter parsers
116
117         By default, parameters are parsed using \c boost::lexical_cast and therefore using \c
118         iostreams. This means, that any type which can be read from a stream can automatically be
119         used as argument type.
120
121         However, argument parsing can be configured by specializing
122         senf::console::ArgumentTraits. See that class for more information.
123
124         \section overload_format Custom return-value formatters
125
126         By default, return values are streamed to an ostream. This automatically allows any
127         streamable type to be used as return value. To add new types or customize the formating, the
128         senf::console::ReturnValueTraits template needs to be specialized for that type. See
129         that class for more information.
130
131         \ingroup console_commands
132      */
133     class ParsedCommandOverloadBase
134         : public CommandOverload
135     {
136     public:
137         typedef boost::intrusive_ptr<ParsedCommandOverloadBase> ptr;
138
139         detail::ArgumentInfoBase & arg(unsigned n) const;
140
141         void doc(std::string const & d);
142
143     protected:
144         ParsedCommandOverloadBase();
145
146         template <class Type> void addParameter();
147
148     private:
149         virtual unsigned v_numArguments() const;
150         virtual void v_argumentDoc(unsigned index, ArgumentDoc & doc) const;
151         virtual std::string v_doc() const;
152
153         typedef std::vector<detail::ArgumentInfoBase::ptr> Parameters;
154         Parameters parameters_;
155         std::string doc_;
156     };
157
158     /** \brief Parsed command overload
159
160         ParsedCommandOverload provides the command overload added to an OverloadedCommandNode for an
161         automatically parsed command.
162
163         This class is normally instantiated automatically when adding a function or member-function
164         pointer as callback to the tree. Manually instantiation this type of overload is \e not
165         simple, since the function signature has to be manipulated correctly to support the optional
166         \c std::ostream first argument.
167
168         \implementation This class is specialized for each supported number of command arguments.
169
170         \todo Implement automatic binding of member functions for parser and formatter
171      */
172     template <class FunctionTraits, class ReturnType, unsigned arity>
173     class ParsedCommandOverload : public ParsedCommandOverloadBase
174     {
175     public:
176         typedef boost::intrusive_ptr<ParsedCommandOverload> ptr;
177
178 #ifdef DOXYGEN
179         static ptr create(Function fn);
180 #endif
181     };
182
183 #ifndef DOXYGEN
184
185 #   define BOOST_PP_ITERATION_PARAMS_1                                  \
186         (4, (0, SENF_CONSOLE_MAX_COMMAND_ARITY,                         \
187              SENF_ABSOLUTE_INCLUDE_PATH(Utils/Console/ParsedCommand.mpp), \
188              1))
189 #   include BOOST_PP_ITERATE()
190
191 #endif
192
193     /** \brief Generic ParsedCommandOverloadBase attributes
194
195         Attributes for parsed commands are not set directly on the node. They are set via a special
196         attributor temporary returned when adding a parsed command to the tree.
197
198         This class is the base class for those attributors. It provides members which do not depend
199         in any way on the exact type of command added.
200
201         \see \ref console_autoparse
202      */
203     class ParsedCommandAttributorBase
204         : public detail::NodeFactory
205     {
206     public:
207         typedef OverloadedCommandNode node_type;
208         typedef OverloadedCommandNode & result_type;
209
210         OverloadedCommandNode & create(DirectoryNode & dir, std::string const & name) const;
211
212     protected:
213         ParsedCommandAttributorBase(ParsedCommandOverloadBase::ptr overload, unsigned index);
214         ParsedCommandAttributorBase(ParsedCommandAttributorBase const & other, unsigned index);
215
216         void argName(std::string const & name);
217         void argDoc(std::string const & doc);
218         void typeName(std::string const & doc);
219         void defaultDoc(std::string const & doc);
220
221         ParsedCommandOverloadBase & overload() const;
222         void overloadDoc(std::string const & doc);
223         void nodeDoc(std::string const & doc);
224         void shortDoc(std::string const & doc);
225
226     private:
227         ParsedCommandOverloadBase::ptr overload_;
228         unsigned index_;
229         boost::optional<std::string> doc_;
230         boost::optional<std::string> shortdoc_;
231     };
232
233     /** \brief Non argument dependent ParsedCommandBase attributes
234
235         Attributes for parsed commands are not set directly on the node. They are set via a special
236         attributor temporary returned when adding a parsed command to the tree.
237
238         This class adds all those members, which do depend on the type of command added (and thereby
239         on that commands signature) but do not depend on the type of any single argument.
240
241         \see \ref console_autoparse
242      */
243     template <class Overload>
244     class ParsedCommandAttributor
245         : public ParsedCommandAttributorBase
246     {
247     public:
248         Overload & overload() const;    ///< Get the command overload
249
250     protected:
251         ParsedCommandAttributor(typename Overload::ptr overload, unsigned index);
252         ParsedCommandAttributor(ParsedCommandAttributorBase const & other, unsigned index);
253
254     private:
255     };
256
257     /** \brief Keyword argument tags
258
259         The tags defined in this namespace are used as keyword arguments via the <a
260         href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
261         library.
262
263         For the keyword tags, the standard C++ scoping rules apply
264         \code
265         // Either qualify them with their complete namespace
266         dir.add(...)
267             .arg( senf::console::kw::name = "name" );
268
269         // Or use a namespace alias
270         namespace kw = senf::console::kw;
271         dir.add(...)
272             .arg( kw::name = "name" );
273
274         // Or import the keywords into the current namespace (beware of name collisions)
275         using namespace senf::console::kw;
276         dir.add(...)
277             .arg( name = "name" );
278         \endcode
279
280         The second alternative is preferred, the <tt>using namespace</tt> directive may be used as
281         long as the keyword names do not clash with another visible symbol.
282
283         \section kw_attributes Argument attribute values
284
285         The keywords are used to set argument attributes.  The keywords \ref default_value and \ref
286         parser influence, how an argument is parsed/interpreted whereas \ref name, \ref description,
287         \ref type_name and \ref default_doc are used to change the arguments documentation:
288         \code
289         void command(int);
290
291         dir.add("command", &command)
292             .arg( kw::name          = "name",
293                   kw::description   = "description",
294                   kw::default_value = 1,
295                   kw::type_name     = "type_name",
296                   kw::default_doc   = "default_doc" );
297         \endcode
298         Will create the following documentation:
299         \htmlonly
300         <pre>
301         Usage:
302             command [name:type_name]
303
304         With:
305             name      description
306                 default: default_doc
307         </pre>
308         \endhtmlonly
309
310         \see \ref senf::console::ParsedArgumentAttributor::arg()
311      */
312     namespace kw {
313         BOOST_PARAMETER_KEYWORD(type, name) ///< Argument name
314                                         /**< Sets the displayed name of the argument. */
315         BOOST_PARAMETER_KEYWORD(type, description) ///< One-line argument description
316                                         /**< This description is shown in the argument
317                                              reference. If several overloads have same-named
318                                              arguments, only one of them should be documented. This
319                                              documentation then applies to all arguments of that
320                                              name. */
321         BOOST_PARAMETER_KEYWORD(type, default_value) ///< Argument default value
322                                         /**< If a default value is specified for an argument, that
323                                              argument is optional. If an overload is called with
324                                              fewer arguments than defined, optional values will be
325                                              used beginning at the last optional argument and going
326                                              forward until all arguments have values assigned. E.g.,
327                                              an overload with 5 parameters \a a - \a e with two
328                                              defaults attached:
329                                              <pre>
330                                              command a:int [b:int] c:int [d:int] e:int
331                                              </pre>
332                                              When calling the overload, the arguments will be
333                                              assigned in the following way:
334                                              <table class="senf fixedwidth">
335                                              <tr>
336                                                <td style="whitespace:no-wrap"><tt>command 1 2</tt></td>
337                                                <td colspan="5">SyntaxErrorException: invalid number of
338                                                  arguments</td>
339                                              </tr>
340                                              <tr>
341                                                <td style="white-space:nowrap"><tt>command 1 2 3</tt></td>
342                                                <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>
343                                              </tr>
344                                              <tr>
345                                                <td style="white-space:nowrap"><tt>command 1 2 3 4</tt></td>
346                                                <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>
347                                              </tr>
348                                              <tr>
349                                                <td style="white-space:nowrap"><tt>command 1 2 3 4 5</tt></td>
350                                                <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>
351                                              </tr>
352                                              <tr>
353                                                <td style="white-space:nowrap"><tt>command 1 2 3 4 5 6</tt></td>
354                                                <td colspan="5">SyntaxErrorException: invalid number of
355                                                  arguments</td>
356                                              </tr>
357                                              </table>
358                                              So, if you use default values as you are used to,
359                                              assigning default values to consecutive trailing
360                                              arguments, they work like they do in C++ and most other
361                                              languages */
362         BOOST_PARAMETER_KEYWORD(type, type_name) ///< Type name of this arguments type
363                                         /**< By default, the type of an argument is extracted from
364                                              the C++ type name by taking the last component of the
365                                              fully scoped name. This value can be changed by setting
366                                              this attribute. */
367         BOOST_PARAMETER_KEYWORD(type, default_doc) ///< String rep of default value
368                                         /**< By default, the default value is documented by
369                                              converting the value to it's string representation
370                                              using the corresponding return value formatter which by
371                                              default uses \c boost::lexical_cast / \c iostreams. The
372                                              displayed value can be changed by setting this
373                                              attribute. */
374         BOOST_PARAMETER_KEYWORD(type, parser) ///< Argument parser
375                                         /**< The argument parser is used to convert the argument
376                                              token list returned by the console/config parser into
377                                              the appropriate value. If not set explicitly, this
378                                              conversion is supplied by the ArgumentTraits
379                                              class.
380
381                                              Setting the \a parser attribute allows to use a custom
382                                              parser. The parser is an arbitrary callable object with
383                                              the signature
384                                              \code
385                                              void parser(senf::console::ParseCommandInfo::TokensRange const & tokens, value_type & out);
386                                              \endcode
387                                              where \c value_type is the type of the overload
388                                              parameter. The parser must read and parse the complete
389                                              \a tokens range and return the parsed value in \a
390                                              out. If the parser fails, it must raise a
391                                              senf::console::SyntaxErrorException. */
392     }
393
394     /** \brief Derived class dependent ParsedCommandBase attributes
395
396         Attributes for parsed commands are not set directly on the node. They are set via a special
397         attributor temporary returned when adding a parsed command to the tree.
398
399         This class adds all those members, which do not depend on any specific argument but which
400         need to return the correct attributor type.
401
402         \see \ref console_autoparse
403      */
404     template <class Overload, class Self, class ReturnType=typename Overload::traits::result_type>
405     class ParsedArgumentAttributorBase
406         : public ParsedCommandAttributor<Overload>
407     {
408     public:
409         Self doc(std::string const & doc); ///< Set documentation for all overloads
410         Self shortdoc(std::string const & doc); ///< Set short documentation for all overloads
411         Self overloadDoc(std::string const & doc); ///< Set overload specific documentation
412         Self formatter(typename Overload::Formatter formatter);
413                                         ///< Set return value formatter
414                                         /**< This member is only available, if the \a ReturnType of
415                                              the installed callback is not \c void.
416
417                                              If \a ReturnType is not \c void, the \a formatter must
418                                              be a callable with a signature compatible with
419                                              \code
420                                              void formatter(ReturnType const & value, std::ostream & os);
421                                              \endcode
422                                              The \a formatter takes the return value of the call \a
423                                              value and writes it properly formated to \a os. */
424
425     protected:
426         ParsedArgumentAttributorBase(typename Overload::ptr overload, unsigned index);
427         ParsedArgumentAttributorBase(ParsedCommandAttributorBase const & other, unsigned index);
428
429     private:
430     };
431
432 #ifndef DOXYGEN
433
434     template <class Overload, class Self>
435     class ParsedArgumentAttributorBase<Overload, Self, void>
436         : public ParsedCommandAttributor<Overload>
437     {
438     public:
439         Self doc(std::string const & doc); ///< Set documentation for all overloads
440         Self shortdoc(std::string const & doc); ///< Set short documentation for all overloads
441         Self overloadDoc(std::string const & doc); ///< Set overload specific documentation
442
443     protected:
444         ParsedArgumentAttributorBase(typename Overload::ptr overload, unsigned index);
445         ParsedArgumentAttributorBase(ParsedCommandAttributorBase const & other, unsigned index);
446
447     private:
448     };
449
450 #endif
451
452     /** \brief Argument dependent ParsedCommandBase attributes
453
454         Attributes for parsed commands are not set directly on the node. They are set via a special
455         attributor temporary returned when adding a parsed command to the tree.
456
457         This class adds all those members, which depend on a specific argument. Each call to \c arg
458         will advance to the next argument.
459
460         \see \ref console_autoparse
461      */
462     template <class Overload, unsigned index, bool flag>
463     class ParsedArgumentAttributor
464         : public ParsedArgumentAttributorBase< Overload,
465                                                 ParsedArgumentAttributor<Overload, index, flag> >
466     {
467         typedef boost::parameter::parameters<
468             kw::type::name,
469             kw::type::description,
470             kw::type::default_value,
471             kw::type::type_name,
472             kw::type::default_doc,
473             kw::type::parser> arg_params;
474
475     public:
476         typedef typename senf::function_traits_arg_type<
477             typename Overload::traits, int(index) >::type arg_type;
478         typedef typename senf::remove_cvref< arg_type >::type value_type;
479         typedef ParsedArgumentAttributor<Overload, index+1> next_type;
480
481         next_type arg() const;          ///< Set argument attributes
482                                         /**< This member changes the attributes for the current
483                                              argument. The attributes are passed to arg() as keyword
484                                              arguments using the <a
485                                              href="http://www.boost.org/doc/libs/1_33_1/libs/parameter/doc/html/index.html">Boost.Parameter</a>
486                                              library.
487                                              \code
488                                              ...
489                                                  .arg( kw::name          = "name",
490                                                        kw::default_value = 1 )
491                                              ...
492                                              \endcode
493                                              The valid keywords are defined in the senf::console::kw
494                                              namespace.
495
496                                              Each call to arg() will increment the argument index
497                                              and advance to the next argument. This member is only
498                                              present, if there is an argument at the current
499                                              index. */
500
501 #ifndef DOXYVEN
502
503 #       define BOOST_PP_ITERATION_PARAMS_1                                                        \
504             (4, (1, BOOST_PARAMETER_MAX_ARITY,                                                    \
505                  SENF_ABSOLUTE_INCLUDE_PATH(Utils/Console/ParsedCommand.mpp),                     \
506                  5))
507 #       include BOOST_PP_ITERATE()
508
509 #endif
510
511     private:
512         explicit ParsedArgumentAttributor(typename Overload::ptr overload);
513         explicit ParsedArgumentAttributor(ParsedCommandAttributorBase const & other);
514
515         template <class ArgumentPack>
516         next_type argInfo(ArgumentPack const & args);
517         template <class Kw, class ArgumentPack>
518         void argInfo(Kw const &, ArgumentPack const &, boost::mpl::false_);
519
520         template <class ArgumentPack>
521         void argInfo(boost::parameter::keyword<kw::type::name> const &,
522                      ArgumentPack const & args, boost::mpl::true_);
523         template <class ArgumentPack>
524         void argInfo(boost::parameter::keyword<kw::type::description> const &,
525                      ArgumentPack const & args, boost::mpl::true_);
526         template <class ArgumentPack>
527         void argInfo(boost::parameter::keyword<kw::type::default_value> const &,
528                      ArgumentPack const & args, boost::mpl::true_);
529         template <class ArgumentPack>
530         void argInfo(boost::parameter::keyword<kw::type::type_name> const &,
531                      ArgumentPack const & args, boost::mpl::true_);
532         template <class ArgumentPack>
533         void argInfo(boost::parameter::keyword<kw::type::default_doc> const &,
534                      ArgumentPack const & args, boost::mpl::true_);
535         template <class ArgumentPack>
536         void argInfo(boost::parameter::keyword<kw::type::parser> const &,
537                      ArgumentPack const & args, boost::mpl::true_);
538
539         next_type next() const;
540
541         void defaultValue(value_type const & value);
542         template <class Fn> void parser(Fn fn);
543
544         template <class O, unsigned i, bool f>
545         friend class ParsedArgumentAttributor;
546
547         friend class detail::ParsedCommandAddNodeAccess;
548     };
549
550 #ifndef DOXYGEN
551
552     template <class Overload, unsigned index>
553     class ParsedArgumentAttributor<Overload, index, false>
554         : public ParsedArgumentAttributorBase< Overload,
555                                                 ParsedArgumentAttributor<Overload, index, false> >
556     {
557     public:
558         typedef OverloadedCommandNode node_type;
559         typedef ParsedArgumentAttributor return_type;
560
561     private:
562         explicit ParsedArgumentAttributor(typename Overload::ptr overload);
563         explicit ParsedArgumentAttributor(ParsedCommandAttributorBase const & other);
564
565         template <class O, unsigned i, bool f>
566         friend class ParsedArgumentAttributor;
567
568         friend class detail::ParsedCommandAddNodeAccess;
569     };
570
571 #endif
572
573 namespace factory {
574
575     template <class Signature>
576     SimpleOverloadAttributor
577     Command(boost::function<Signature> fn,
578             typename boost::enable_if_c<detail::ParsedCommandTraits<Signature>::is_simple>::type * = 0);
579
580     template <class Function>
581     SimpleOverloadAttributor
582     Command(Function fn,
583             typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_simple>::type * = 0);
584
585     template <class Owner, class Member>
586     SimpleOverloadAttributor
587     Command(Member memfn, Owner * owner,
588             typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0,
589             typename boost::enable_if_c<detail::ParsedCommandTraits<Member>::is_simple>::type * = 0);
590
591     template <class Owner, class Member>
592     SimpleOverloadAttributor
593     Command(Member memfn, Owner const * owner,
594             typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0,
595             typename boost::enable_if_c<detail::ParsedCommandTraits<Member>::is_simple>::type * = 0);
596
597     template <class CastTo, class Signature>
598     typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
599     Command(boost::function<Signature> fn);
600
601     template <class CastTo, class Function>
602     typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
603     Command(Function fn,
604             typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_callable>::type * = 0,
605             typename boost::disable_if<boost::is_member_function_pointer<Function> >::type * = 0);
606
607     template <class Signature>
608     typename senf::console::detail::ParsedCommandTraits<Signature>::Attributor
609     Command(boost::function<Signature> fn);
610
611     template <class Function>
612     typename senf::console::detail::ParsedCommandTraits<Function>::Attributor
613     Command(Function fn,
614             typename boost::enable_if_c<detail::ParsedCommandTraits<Function>::is_callable>::type * = 0,
615             typename boost::disable_if<boost::is_member_function_pointer<Function> >::type * = 0);
616
617     template <class Owner, class Member>
618     typename senf::console::detail::ParsedCommandTraits<Member>::Attributor
619     Command(Member memfn, Owner * owner,
620             typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
621
622     template <class Owner, class Member>
623     typename senf::console::detail::ParsedCommandTraits<Member>::Attributor
624     Command(Member memfn, Owner const * owner,
625             typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
626
627     template <class CastTo, class Owner, class Member>
628     typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
629     Command(Member memfn, Owner * owner,
630             typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
631
632     template <class CastTo, class Owner, class Member>
633     typename senf::console::detail::ParsedCommandTraits<CastTo>::Attributor
634     Command(Member memfn, Owner const * owner,
635             typename boost::enable_if<boost::is_member_function_pointer<Member> >::type * = 0);
636
637
638 }}}
639
640 ///////////////////////////////hh.e////////////////////////////////////////
641 #include "ParsedCommand.cci"
642 #include "ParsedCommand.ct"
643 #include "ParsedCommand.cti"
644 #endif
645
646 \f
647 // Local Variables:
648 // mode: c++
649 // fill-column: 100
650 // comment-column: 40
651 // c-file-style: "senf"
652 // indent-tabs-mode: nil
653 // ispell-local-dictionary: "american"
654 // compile-command: "scons -u test"
655 // End: