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