PPI: Allow connecting two MultiConnectorMixin modules
g0dil [Mon, 31 Aug 2009 23:29:06 +0000 (23:29 +0000)]
git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@1360 270642c3-0616-0410-b53a-bc976706d245

SConstruct
senf/PPI/MultiConnectorMixin.cti
senf/PPI/MultiConnectorMixin.hh
senf/PPI/MultiConnectorMixin.ih
senf/PPI/MultiConnectorMixin.mpp
senf/PPI/MultiConnectorMixin.test.cc
senf/PPI/Setup.cti
senf/Utils/type_traits.hh
senf/Utils/type_traits.test.cc

index ff96d8d..6b55257 100644 (file)
@@ -16,7 +16,6 @@ env = Environment()
 
 # Load all the local SCons tools
 env.Tool('Doxygen')
-env.Tool('Doxygen')
 env.Tool('Dia2Png')
 env.Tool('PkgDraw')
 env.Tool('InstallSubdir')
index 3df16d8..eabe309 100644 (file)
@@ -110,6 +110,14 @@ senf::ppi::connect(Source & source, Target & target , A1 const & a1)
             3 ))
 #include BOOST_PP_ITERATE()
 
+// Include 'senf::ppi::detail implementation' from MultiConnectorMixin.mpp
+#define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
+            0, \
+            SENF_MULTI_CONNECTOR_MAX_ARGS2,                           \
+            SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
+            7 ))
+#include BOOST_PP_ITERATE()
+
 #endif
 
 ///////////////////////////////cti.e///////////////////////////////////////
index c154657..4e248ee 100644 (file)
 #include "Connectors.hh"
 #include "Setup.hh"
 
-#include "MultiConnectorMixin.mpp"
-#include "MultiConnectorMixin.ih"
-///////////////////////////////hh.p////////////////////////////////////////
-
 #ifndef SENF_MULTI_CONNECTOR_MAX_ARGS
 #define SENF_MULTI_CONNECTOR_MAX_ARGS 3
+#define SENF_MULTI_CONNECTOR_MAX_ARGS2 6
 #endif
 
+#include "MultiConnectorMixin.mpp"
+#include "MultiConnectorMixin.ih"
+///////////////////////////////hh.p////////////////////////////////////////
+
 namespace senf {
 namespace ppi {
     
@@ -73,9 +74,14 @@ namespace ppi {
     MultiConnectorTarget::ConnectorType & connect(
         Source & source, MultiConnectorTarget & target, A1 const & a1);
 
+    template <class MultiConnectorSource, class MultiConnectorTarget, class A1, class A2>
+    std::pair<MultiConnectorSource::ConnectorType &, MultiConnectorTarget::ConnectorType &>
+    connect(
+        MultiConnectorSource & source, MultiConnectorTarget & target, A1 const & a1, A2 const & a2);
+
 #else
 
-    // Include 'senf::ppi::namespace member declarations' from MultiConnectorMixin.mpp
+    // Include 'senf::ppi namespace member declarations' from MultiConnectorMixin.mpp
 #   define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
             0, \
             SENF_MULTI_CONNECTOR_MAX_ARGS, \
@@ -83,10 +89,19 @@ namespace ppi {
             2 ))
 #   include BOOST_PP_ITERATE()
 
+#   define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
+            0, \
+            SENF_MULTI_CONNECTOR_MAX_ARGS2, \
+            SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
+            6 ))
+#   include BOOST_PP_ITERATE()
+
 #endif
 
 namespace module {
 
+    namespace detail { class MultiConnectorMixinAccess; }
+
     /** \brief Multi connector management
 
         This mixin provides a module with support for a runtime configurable number of input or
@@ -249,18 +264,6 @@ namespace module {
         tempalte <class A1>
         ConnectorType_ & newConnector(A1 const & a1);
 
-        // See above for an additional note regarding the boost::enable_if in the real
-        // implementation
-        
-        template <class Source, class Target, class A1>
-        friend Source::ConnectorType & senf::ppi::connect(Source & source, 
-                                                          Target & target, 
-                                                          A1 const & a1);
-
-        template <class Source, class Target, class A1>
-        friend Target::ConnectorType & senf::ppi::connect(Source & source,
-                                                          Target & target,
-                                                          A1 const & a1);
 #endif
 #ifndef DOXYGEN
 
@@ -272,7 +275,16 @@ namespace module {
             1 ))
 #       include BOOST_PP_ITERATE()
 
+#       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
+            0, \
+            SENF_MULTI_CONNECTOR_MAX_ARGS2, \
+            SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
+            9 ))
+#       include BOOST_PP_ITERATE()
+
 #endif
+
+        friend class detail::MultiConnectorMixinAccess;
         
         ContainerType_ connectors_;
     };
@@ -323,6 +335,15 @@ namespace module {
             1 ))
 #       include BOOST_PP_ITERATE()
         
+#       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
+            0, \
+            SENF_MULTI_CONNECTOR_MAX_ARGS2, \
+            SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
+            9 ))
+#       include BOOST_PP_ITERATE()
+
+        friend class detail::MultiConnectorMixinAccess;
+
         ContainerType_ connectors_;
     };
 
@@ -364,6 +385,15 @@ namespace module {
             SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
             1 ))
 #       include BOOST_PP_ITERATE()
+
+#       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
+            0, \
+            SENF_MULTI_CONNECTOR_MAX_ARGS2, \
+            SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
+            9 ))
+#       include BOOST_PP_ITERATE()
+
+        friend class detail::MultiConnectorMixinAccess;
     };
 
 #endif
index 0d96226..eff8769 100644 (file)
@@ -35,6 +35,16 @@ namespace ppi {
 namespace module {
 namespace detail {
 
+    struct MultiConnectorMixinAccess
+    {
+#       define BOOST_PP_ITERATION_PARAMS_1 (4, ( \
+            0, \
+            SENF_MULTI_CONNECTOR_MAX_ARGS,                              \
+            SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp),    \
+            8 ))
+#       include BOOST_PP_ITERATE()
+    };
+
     template <class KeyType, class ConnectorType>
     struct MultiConnectorDefaultContainer 
     { 
@@ -58,6 +68,52 @@ namespace detail {
               ppi::detail::DisableStandardInput, ppi::detail::DisableStandardOutput >
     {};
 
+    template <class T> senf::mpl::rv<0> is_multiconnector_(T *, ...);
+    template <class T> senf::mpl::rv<1> is_multiconnector_(
+        T *,
+        typename boost::enable_if<boost::is_base_of<connector::OutputConnector, 
+                                                    typename T::ConnectorType>, 
+        int>::type);
+    template <class T> senf::mpl::rv<2> is_multiconnector_(
+        T *,
+        typename boost::enable_if<boost::is_base_of<connector::InputConnector, 
+                                                    typename T::ConnectorType>, 
+        int>::type);
+
+    template <class T, unsigned N>
+    struct is_multiconnector_source_
+        : public boost::false_type
+    {};
+
+    template <class T>
+    struct is_multiconnector_source_<T, 1u>
+        : public boost::true_type
+    {};
+
+    template <class T>
+    struct is_multiconnector_source
+        : public is_multiconnector_source_<
+              T, SENF_MPL_RV(is_multiconnector_<T>(static_cast<T*>(0),0))>
+    {};
+
+    template <class T, unsigned N>
+    struct is_multiconnector_target_
+        : public boost::false_type
+    {};
+
+    template <class T>
+    struct is_multiconnector_target_<T, 2u>
+        : public boost::true_type
+    {};
+
+    template <class T>
+    struct is_multiconnector_target
+        : public is_multiconnector_target_<
+              T, SENF_MPL_RV(is_multiconnector_<T>(static_cast<T*>(0),0))>
+    {};
+
+
+
 }}}}
 
 ///////////////////////////////ih.e////////////////////////////////////////
index aeb5dfd..ac56abe 100644 (file)
@@ -35,6 +35,9 @@
 #include <boost/preprocessor/repetition/enum_trailing_params.hpp>
 #include <boost/preprocessor/repetition/enum_trailing_binary_params.hpp> 
 #include <boost/type_traits/is_base_of.hpp>
+#include <boost/mpl/and.hpp>
+#include <boost/mpl/not.hpp>
+#include <senf/Utils/type_traits.hh>
 
 // ///////////////////////////mpp.p////////////////////////////////////////
 #elif BOOST_PP_IS_ITERATING // ////////////////////////////////////////////
 #define mpp_CallParamsKomma()                                           \
     BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_ITERATION(), a)
 
+// Same as above but for outer loop in nested loops
+#define mpp_TplParamsKomma2()                                            \
+    BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_FRAME_ITERATION(1), class B)
+#define mpp_FnParams2()                                                  \
+    BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_FRAME_ITERATION(1), B, const & a)
+#define mpp_FnParamsKomma2()                                             \
+    BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(BOOST_PP_FRAME_ITERATION(1), B, const & b)
+#define mpp_CallParams2()                                                \
+    BOOST_PP_ENUM_PARAMS(BOOST_PP_FRAME_ITERATION(1), b)
+#define mpp_CallParamsKomma2()                                           \
+    BOOST_PP_ENUM_TRAILING_PARAMS(BOOST_PP_FRAME_ITERATION(1), b)
+
 // ////////////////////////////////////////////////////////////////////////
 #if BOOST_PP_ITERATION_FLAGS()==1 // //////////////////////////////////////
 // ////////////////////////////////////////////////////////////////////////
 mpp_TplParams()
 ConnectorType_ & newConnector( mpp_FnParams() );
 
-template <class Source, class Target mpp_TplParamsKomma()>
-friend typename boost::enable_if<
-        boost::is_base_of<connector::OutputConnector, typename Source::ConnectorType>,
-        typename Source::ConnectorType & >::type
-    senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma());
+// ////////////////////////////////////////////////////////////////////////
+#elif BOOST_PP_ITERATION_FLAGS()==9 // //////////////////////////////////////
+// ////////////////////////////////////////////////////////////////////////
+// MultiConnectorMixin member declaration
 
 template <class Source, class Target mpp_TplParamsKomma()>
-friend typename boost::enable_if<
-        boost::is_base_of<connector::InputConnector, typename Target::ConnectorType>,
-        typename Target::ConnectorType & >::type
-    senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma());
+static std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
+connect_(Source & source, Target & target mpp_FnParamsKomma());
 
 // ////////////////////////////////////////////////////////////////////////
 #elif BOOST_PP_ITERATION_FLAGS()==2 // ////////////////////////////////////
 // ////////////////////////////////////////////////////////////////////////
 // senf::ppi namespace member declaration
 
+// Here the reference to Source::ConnectorType / Target::ConnectorType
+// works like enable_if, since only MultiConnector modules have those members
+
 template <class Source, class Target mpp_TplParamsKomma()>
 typename boost::enable_if<
-    boost::is_base_of<connector::OutputConnector, typename Source::ConnectorType>,
+    boost::mpl::and_<
+        senf::ppi::module::detail::is_multiconnector_source<Source>,
+        boost::mpl::not_< senf::ppi::module::detail::is_multiconnector_target<Target> > >,
     typename Source::ConnectorType & >::type
 connect(Source & source, Target & target mpp_FnParamsKomma());
 
 template <class Source, class Target mpp_TplParamsKomma()>
 typename boost::enable_if<
-    boost::is_base_of<connector::InputConnector, typename Target::ConnectorType>,
+    boost::mpl::and_<
+        boost::mpl::not_< senf::ppi::module::detail::is_multiconnector_source<Source> >,
+        senf::ppi::module::detail::is_multiconnector_target<Target> >,
     typename Target::ConnectorType & >::type
 connect(Source & source, Target & target mpp_FnParamsKomma());
 
+#define BOOST_PP_ITERATION_PARAMS_2 (4, (\
+        0, \
+        SENF_MULTI_CONNECTOR_MAX_ARGS, \
+        SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
+        4 ))
+#include BOOST_PP_ITERATE()
+
+// ////////////////////////////////////////////////////////////////////////
+#elif BOOST_PP_ITERATION_FLAGS()==6 // ////////////////////////////////////
+// ////////////////////////////////////////////////////////////////////////
+// senf::ppi namespace member declaration (nested)
+
+template <class Source, class Target mpp_TplParamsKomma()>
+typename boost::enable_if<
+    boost::mpl::and_<
+        boost::is_base_of<connector::OutputConnector, typename Source::ConnectorType>,
+        boost::is_base_of<connector::InputConnector, typename Target::ConnectorType> >,
+    std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
+connect(Source & source, Target & target mpp_FnParamsKomma());
+
+// ////////////////////////////////////////////////////////////////////////
+#elif BOOST_PP_ITERATION_FLAGS()==4 // ////////////////////////////////////
+// ////////////////////////////////////////////////////////////////////////
+// senf::ppi::detail namespace member declaration (nested iteration)
+
+namespace detail {
+
+template <class Fn, class Source, class Target mpp_TplParamsKomma() mpp_TplParamsKomma2()>
+typename boost::enable_if_c<
+    senf::function_arity<Fn>::value == BOOST_PP_ITERATION()+1,
+    std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
+connect_(Fn, Source & source, Target & target mpp_FnParamsKomma() mpp_FnParamsKomma2());
+
+}
+
 // ////////////////////////////////////////////////////////////////////////
 #elif BOOST_PP_ITERATION_FLAGS()==3 // ////////////////////////////////////
 // ////////////////////////////////////////////////////////////////////////
@@ -148,35 +202,152 @@ newConnector(mpp_FnParams())
 }
 
 ////////////////////////////////////////
+// senf::ppi::module::detail::MultiConnectorMixinAccess members
+
+template <class Module mpp_TplParamsKomma()>
+typename Module::ConnectorType & 
+senf::ppi::module::detail::MultiConnectorMixinAccess::newConnector(
+    Module & module mpp_FnParamsKomma())
+{
+    return module.newConnector(mpp_CallParams());
+}
+
+template <class Source, class Target mpp_TplParamsKomma()>
+std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
+senf::ppi::module::detail::MultiConnectorMixinAccess::connect(
+    Source & source, Target & target mpp_FnParamsKomma())
+{
+    return Source::connect_(source, target mpp_CallParamsKomma());
+}
+
+////////////////////////////////////////
 // senf::ppi::connect
 
 template <class Source, class Target mpp_TplParamsKomma()>
 typename boost::enable_if<
-    boost::is_base_of<senf::ppi::connector::OutputConnector, typename Source::ConnectorType>,
+    boost::mpl::and_<
+        senf::ppi::module::detail::is_multiconnector_source<Source>,
+        boost::mpl::not_< senf::ppi::module::detail::is_multiconnector_target<Target> > >,
     typename Source::ConnectorType & >::type
 senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
 {
-    typename Source::ConnectorType & c (source.newConnector(mpp_CallParams()));
+    typename Source::ConnectorType & c (
+        module::detail::MultiConnectorMixinAccess::newConnector(source mpp_CallParamsKomma()));
     connect(c, target);
     return c;
 }
 
 template <class Source, class Target mpp_TplParamsKomma()>
 typename boost::enable_if<
-    boost::is_base_of<senf::ppi::connector::InputConnector, typename Target::ConnectorType>,
+    boost::mpl::and_<
+        boost::mpl::not_< senf::ppi::module::detail::is_multiconnector_source<Source> >,
+        senf::ppi::module::detail::is_multiconnector_target<Target> >,
     typename Target::ConnectorType & >::type
 senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
 {
-    typename Target::ConnectorType & c (target.newConnector(mpp_CallParams()));
+    typename Target::ConnectorType & c (
+        module::detail::MultiConnectorMixinAccess::newConnector(target mpp_CallParamsKomma()));
     connect(source, c);
     return c;
 }
 
+#define BOOST_PP_ITERATION_PARAMS_2 (4, (\
+        0, \
+        SENF_MULTI_CONNECTOR_MAX_ARGS, \
+        SENF_ABSOLUTE_INCLUDE_PATH(PPI/MultiConnectorMixin.mpp), \
+        5 ))
+#include BOOST_PP_ITERATE()
+
+// ////////////////////////////////////////////////////////////////////////
+#elif BOOST_PP_ITERATION_FLAGS()==5 // ////////////////////////////////////
+// ////////////////////////////////////////////////////////////////////////
+// Implementation for nested iteration
+
+template <class Fn, class Source, class Target mpp_TplParamsKomma() mpp_TplParamsKomma2()>
+typename boost::enable_if_c<
+    senf::function_arity<Fn>::value == BOOST_PP_ITERATION()+1,
+    std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
+senf::ppi::detail::connect_(Fn, Source & source, Target & target 
+                            mpp_FnParamsKomma() mpp_FnParamsKomma2())
+{
+    typename Source::ConnectorType & s (
+        module::detail::MultiConnectorMixinAccess::newConnector(source mpp_CallParamsKomma()));
+    typename Target::ConnectorType & t (
+        module::detail::MultiConnectorMixinAccess::newConnector(target mpp_CallParamsKomma2()));
+    connect(s,t);
+    return std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>(s,t);
+}
+
+// ////////////////////////////////////////////////////////////////////////
+#elif BOOST_PP_ITERATION_FLAGS()==7 // ////////////////////////////////////
+// ////////////////////////////////////////////////////////////////////////
+// Implementation
+
+template <class Self_, class ConnectorType_, class KeyType_, class ContainerType_>
+template <class Source, class Target mpp_TplParamsKomma()>
+std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
+senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,KeyType_,ContainerType_>::
+connect_(Source & source, Target & target mpp_FnParamsKomma())
+{
+    return senf::ppi::detail::connect_(
+        & Self_::connectorSetup, source, target mpp_CallParamsKomma());
+}
+
+template <class Self_, class ConnectorType_, class ContainerType_>
+template <class Source, class Target mpp_TplParamsKomma()>
+std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
+senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,ContainerType_>::
+connect_(Source & source, Target & target mpp_FnParamsKomma())
+{
+    return senf::ppi::detail::connect_(
+        & Self_::connectorSetup, source, target mpp_CallParamsKomma());
+}
+
+template <class Self_, class ConnectorType_>
+template <class Source, class Target mpp_TplParamsKomma()>
+std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
+senf::ppi::module::MultiConnectorMixin<Self_,ConnectorType_,void,void>::
+connect_(Source & source, Target & target mpp_FnParamsKomma())
+{
+    return senf::ppi::detail::connect_(
+        & Self_::connectorSetup, source, target mpp_CallParamsKomma());
+}
+
+template <class Source, class Target mpp_TplParamsKomma()>
+typename boost::enable_if<
+    boost::mpl::and_<
+        boost::is_base_of<senf::ppi::connector::OutputConnector, typename Source::ConnectorType>,
+        boost::is_base_of<senf::ppi::connector::InputConnector, typename Target::ConnectorType> >,
+    std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &> >::type
+senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
+{
+    return module::detail::MultiConnectorMixinAccess::connect(
+        source, target mpp_CallParamsKomma());
+}
+
+// ////////////////////////////////////////////////////////////////////////
+#elif BOOST_PP_ITERATION_FLAGS()==8 // ////////////////////////////////////
+// ////////////////////////////////////////////////////////////////////////
+// senf::ppi::module::detail::MultiConnectorMixinAccess members
+
+template <class Module mpp_TplParamsKomma()>
+static typename Module::ConnectorType & 
+newConnector(Module & module mpp_FnParamsKomma());
+
+template <class Source, class Target mpp_TplParamsKomma()>
+static std::pair<typename Source::ConnectorType &, typename Target::ConnectorType &>
+connect(Source & source, Target & target mpp_FnParamsKomma());
+
 // ////////////////////////////////////////////////////////////////////////
 #endif // /////////////////////////////////////////////////////////////////
 // ////////////////////////////////////////////////////////////////////////
 // Undefine local Macros
 
+#undef mpp_CallParamsKomma2
+#undef mpp_CallParams2
+#undef mpp_FnParamsKomma2
+#undef mpp_FnParams2
+#undef mpp_TplParamsKomma2
 #undef mpp_CallParamsKomma
 #undef mpp_CallParams
 #undef mpp_FnParamsKomma
@@ -196,7 +367,7 @@ senf::ppi::connect(Source & source, Target & target mpp_FnParamsKomma())
  (search-backward "#define") (forward-line 1) (point))))) (point))))
  (reverse-region b e) (shell-command-on-region b e "grep -F '#define'" nil
  t) (goto-char b) (while (looking-at "#define") (delete-char 7) (insert
- "#undef") (skip-chars-forward " ") (re-search-forward "[^a-zA-Z_]")
+ "#undef") (skip-chars-forward " ") (re-search-forward "[^a-zA-Z0-9_]")
  (delete-region (1- (point)) (progn (end-of-line) (point))) (forward-line
  1))))
 */
index 83f6532..44d6402 100644 (file)
@@ -91,6 +91,13 @@ namespace {
     { os << value.value; return os; }
 }
 
+BOOST_AUTO_UNIT_TEST(multiConnectorTraits)
+{
+    BOOST_STATIC_ASSERT( senf::ppi::module::detail::is_multiconnector_source<MyModule>::value );
+    BOOST_STATIC_ASSERT( ! senf::ppi::module::detail::is_multiconnector_target<MyModule>::value );
+}
+
+
 BOOST_AUTO_UNIT_TEST(multiConnectorMixin_userContainer)
 {
     debug::ActiveSource source;
@@ -114,8 +121,6 @@ BOOST_AUTO_UNIT_TEST(multiConnectorMixin_userContainer)
 
 BOOST_AUTO_UNIT_TEST(multiConnectorMixin_multipleModules)
 {
-    // This test fails!
-    /*
     debug::ActiveSource source;
     debug::PassiveSink sink;
     module::PassiveJoin join1;
@@ -135,7 +140,6 @@ BOOST_AUTO_UNIT_TEST(multiConnectorMixin_multipleModules)
     source.submit(p);
     BOOST_CHECK_EQUAL( sink.size(), 1u );
     BOOST_CHECK( sink.pop_front() == p );
-    */
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////
index ca6e672..7245c5c 100644 (file)
@@ -58,8 +58,8 @@ prefix_ void senf::ppi::
 connect(T1 & source, T2 & target,
         typename boost::disable_if< boost::is_base_of<connector::Connector, T1> >::type *,
         typename boost::disable_if< boost::is_base_of<connector::Connector, T2> >::type *,
-        typename boost::disable_if< boost::is_base_of<detail::DisableStandardOutput, T1> >:: type *,
-        typename boost::disable_if< boost::is_base_of<detail::DisableStandardInput, T2> >:: type *)
+        typename boost::disable_if< boost::is_base_of<detail::DisableStandardOutput, T1> >::type *,
+        typename boost::disable_if< boost::is_base_of<detail::DisableStandardInput, T2> >::type *)
 {
     connect(source.output, target.input);
 }
index a728ac0..8f58122 100644 (file)
@@ -243,6 +243,14 @@ namespace senf
         : public boost::remove_cv< typename boost::remove_reference<T>::type >
     {};
 
+    template < class T >
+    struct function_arity
+        : public boost::integral_constant<
+              unsigned,
+              boost::function_traits<
+                  typename senf::remove_any_pointer<T>::type>::arity>
+    {};
+
   ///}
 
 #ifndef DOXYGEN
index c446157..fb9fe5f 100644 (file)
@@ -103,6 +103,13 @@ BOOST_AUTO_UNIT_TEST(typeTraits)
         senf::remove_cvref<int const &>::type,
         int
     >::value ));
+
+    BOOST_STATIC_ASSERT(( senf::function_arity<void ()>::value == 0 ));
+    BOOST_STATIC_ASSERT(( senf::function_arity<void (int,int)>::value == 2 ));
+    BOOST_STATIC_ASSERT(( senf::function_arity<void (*)()>::value == 0 ));
+    BOOST_STATIC_ASSERT(( senf::function_arity<void (*)(int,int)>::value == 2 ));
+    BOOST_STATIC_ASSERT(( senf::function_arity<void (Class::*)()>::value == 0 ));
+    BOOST_STATIC_ASSERT(( senf::function_arity<void (Class::*)(int,int)>::value == 2 ));
 }
 
 ///////////////////////////////cc.e////////////////////////////////////////