From 3e205156640dcac194d95afa182ef8fd953a01db Mon Sep 17 00:00:00 2001 From: Stefano Avallone Date: Wed, 14 Nov 2018 10:51:57 +0100 Subject: [PATCH] core: Use std::function to implement callbacks --- src/core/model/callback.h | 1812 +++-------------- src/core/model/unix-fd-reader.cc | 2 +- src/core/test/callback-test-suite.cc | 203 +- src/core/test/traced-callback-test-suite.cc | 26 +- src/internet/model/icmpv4-l4-protocol.cc | 2 +- src/internet/model/icmpv6-l4-protocol.cc | 2 +- .../model/matrix-based-channel-model.h | 2 +- src/wifi/test/wifi-primary-channels-test.cc | 2 +- 8 files changed, 526 insertions(+), 1525 deletions(-) diff --git a/src/core/model/callback.h b/src/core/model/callback.h index 76d5365a3..43cecd90a 100644 --- a/src/core/model/callback.h +++ b/src/core/model/callback.h @@ -15,7 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * Author: Mathieu Lacage + * Authors: Mathieu Lacage + * Stefano Avallone */ #ifndef CALLBACK_H @@ -24,11 +25,14 @@ #include "ptr.h" #include "fatal-error.h" #include "empty.h" -#include "type-traits.h" #include "attribute.h" #include "attribute-helper.h" #include "simple-ref-count.h" #include +#include +#include +#include +#include /** * \file @@ -69,36 +73,6 @@ namespace ns3 { */ -/** - * \ingroup callbackimpl - * - * Trait class to convert a pointer into a reference, - * used by MemPtrCallBackImpl - * \tparam T \deduced The type being converted. - */ -template -struct CallbackTraits; - -/** - * \ingroup callbackimpl - * - * Trait class to convert a pointer into a reference, - * used by MemPtrCallBackImpl - * \tparam T \deduced The type being converted. - */ -template -struct CallbackTraits -{ - /** - * \param [in] p Object pointer - * \return A reference to the object pointed to by p - */ - static T & GetReference (T * const p) - { - return *p; - } -}; - /** * \ingroup callbackimpl * Abstract base class for CallbackImpl @@ -152,1030 +126,222 @@ protected: } }; -/** - * \ingroup callbackimpl - * The unqualified CallbackImpl class - * \tparam R \explicit The return type of the Callback. - * The remaining template arguments are the types of any arguments - * to the Callback. - */ -template -class CallbackImpl; /** * \ingroup callbackimpl - * CallbackImpl classes with varying numbers of argument types + * Abstract base class for CallbackComponent. + * Provides equality test. + */ +class CallbackComponentBase +{ +public: + /** Virtual destructor */ + virtual ~CallbackComponentBase () {} + /** + * Equality test + * + * \param [in] other CallbackComponent Ptr + * \return \c true if we are equal + */ + virtual bool IsEqual (std::shared_ptr other) const = 0; +}; + +/** + * \ingroup callbackimpl + * Stores a component of a callback, i.e., the callable object + * or a bound argument. The purpose of this class is to test + * the equality of the components of two callbacks. * - * @{ + * \tparam T The type of the callback component. + * \tparam isComparable whether this callback component can be compared to others of the same type */ -/** CallbackImpl class with no arguments. */ -template -class CallbackImpl : public CallbackImplBase -{ -public: - virtual ~CallbackImpl () - {} - virtual R operator() (void) = 0; //!< \return Callback value - virtual std::string GetTypeid (void) const - { - return DoGetTypeid (); - } - /** \copydoc GetTypeid(). */ - static std::string DoGetTypeid (void) - { - static std::string id = "CallbackImpl<" + - GetCppTypeid () + - ">"; - return id; - } -}; -/** CallbackImpl class with one argument. */ -template -class CallbackImpl : public CallbackImplBase -{ -public: - virtual ~CallbackImpl () - {} - virtual R operator() (T1) = 0; //!< \return Callback value - virtual std::string GetTypeid (void) const - { - return DoGetTypeid (); - } - /** \copydoc GetTypeid(). */ - static std::string DoGetTypeid (void) - { - static std::string id = "CallbackImpl<" + - GetCppTypeid () + "," + - GetCppTypeid () + - ">"; - return id; - } -}; -/** CallbackImpl class with two arguments. */ -template -class CallbackImpl : public CallbackImplBase -{ -public: - virtual ~CallbackImpl () - {} - virtual R operator() (T1, T2) = 0; //!< \return Callback value - virtual std::string GetTypeid (void) const - { - return DoGetTypeid (); - } - /** \copydoc GetTypeid(). */ - static std::string DoGetTypeid (void) - { - static std::string id = "CallbackImpl<" + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + - ">"; - return id; - } -}; -/** CallbackImpl class with three arguments. */ -template -class CallbackImpl : public CallbackImplBase -{ -public: - virtual ~CallbackImpl () - {} - virtual R operator() (T1, T2, T3) = 0; //!< \return Callback value - virtual std::string GetTypeid (void) const - { - return DoGetTypeid (); - } - /** \copydoc GetTypeid(). */ - static std::string DoGetTypeid (void) - { - static std::string id = "CallbackImpl<" + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + - ">"; - return id; - } -}; -/** CallbackImpl class with four arguments. */ -template -class CallbackImpl : public CallbackImplBase -{ -public: - virtual ~CallbackImpl () - {} - virtual R operator() (T1, T2, T3, T4) = 0; //!< \return Callback value - virtual std::string GetTypeid (void) const - { - return DoGetTypeid (); - } - /** \copydoc GetTypeid(). */ - static std::string DoGetTypeid (void) - { - static std::string id = "CallbackImpl<" + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + - ">"; - return id; - } -}; -/** CallbackImpl class with five arguments. */ -template -class CallbackImpl : public CallbackImplBase -{ -public: - virtual ~CallbackImpl () - {} - virtual R operator() (T1, T2, T3, T4, T5) = 0; //!< \return Callback value - virtual std::string GetTypeid (void) const - { - return DoGetTypeid (); - } - /** \copydoc GetTypeid(). */ - static std::string DoGetTypeid (void) - { - static std::string id = "CallbackImpl<" + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + - ">"; - return id; - } -}; -/** CallbackImpl class with six arguments. */ -template -class CallbackImpl : public CallbackImplBase -{ -public: - virtual ~CallbackImpl () - {} - virtual R operator() (T1, T2, T3, T4, T5, T6) = 0; //!< \return Callback value - virtual std::string GetTypeid (void) const - { - return DoGetTypeid (); - } - /** \copydoc GetTypeid(). */ - static std::string DoGetTypeid (void) - { - static std::string id = "CallbackImpl<" + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + - ">"; - return id; - } -}; -/** CallbackImpl class with seven arguments. */ -template -class CallbackImpl : public CallbackImplBase -{ -public: - virtual ~CallbackImpl () - {} - virtual R operator() (T1, T2, T3, T4, T5, T6, T7) = 0; //!< \return Callback value - virtual std::string GetTypeid (void) const - { - return DoGetTypeid (); - } - /** \copydoc GetTypeid(). */ - static std::string DoGetTypeid (void) - { - static std::string id = "CallbackImpl<" + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + - ">"; - return id; - } -}; -/** CallbackImpl class with eight arguments. */ -template -class CallbackImpl : public CallbackImplBase -{ -public: - virtual ~CallbackImpl () - {} - virtual R operator() (T1, T2, T3, T4, T5, T6, T7, T8) = 0; //!< \return Callback value - virtual std::string GetTypeid (void) const - { - return DoGetTypeid (); - } - /** \copydoc GetTypeid(). */ - static std::string DoGetTypeid (void) - { - static std::string id = "CallbackImpl<" + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + - ">"; - return id; - } -}; -/** CallbackImpl class with nine arguments. */ -template -class CallbackImpl : public CallbackImplBase -{ -public: - virtual ~CallbackImpl () - {} - virtual R operator() (T1, T2, T3, T4, T5, T6, T7, T8, T9) = 0; //!< \return Callback value - virtual std::string GetTypeid (void) const - { - return DoGetTypeid (); - } - /** \copydoc GetTypeid(). */ - static std::string DoGetTypeid (void) - { - static std::string id = "CallbackImpl<" + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + "," + - GetCppTypeid () + - ">"; - return id; - } -}; -/**@}*/ - - -/** - * \ingroup callbackimpl - * CallbackImpl with functors - * \tparam T \deduced Function pointer type. - */ -template -class FunctorCallbackImpl : public CallbackImpl +template +class CallbackComponent : public CallbackComponentBase { public: /** - * Construct from a functor + * Constructor * - * \param [in] functor The functor + * \param [in] t The value of the callback component */ - FunctorCallbackImpl (T const &functor) - : m_functor (functor) - {} + CallbackComponent (const T& t) + : m_comp (t) {} + /** - * Functor with varying numbers of arguments - * @{ - */ - /** \return Callback value */ - R operator() (void) - { - return m_functor (); - } - /** - * \param [in] a1 First argument - * \return Callback value - */ - R operator() (T1 a1) - { - return m_functor (a1); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2) - { - return m_functor (a1,a2); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3) - { - return m_functor (a1,a2,a3); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4) - { - return m_functor (a1,a2,a3,a4); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) - { - return m_functor (a1,a2,a3,a4,a5); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) - { - return m_functor (a1,a2,a3,a4,a5,a6); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7) - { - return m_functor (a1,a2,a3,a4,a5,a6,a7); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \param [in] a8 eighth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8) - { - return m_functor (a1,a2,a3,a4,a5,a6,a7,a8); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \param [in] a8 eighth argument - * \param [in] a9 ninth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8,T9 a9) - { - return m_functor (a1,a2,a3,a4,a5,a6,a7,a8,a9); - } - /**@}*/ - /** - * Equality test. + * Equality test between the values of two components * - * \param [in] other CallbackImpl Ptr - * \return \c true if this and other have the same functor + * \param [in] other CallbackComponentBase Ptr + * \return \c true if we are equal */ - virtual bool IsEqual (Ptr other) const + bool IsEqual (std::shared_ptr other) const { - FunctorCallbackImpl const *otherDerived = - dynamic_cast const *> (PeekPointer (other)); - if (otherDerived == 0) - { - return false; - } - else if (otherDerived->m_functor != m_functor) + auto p = std::dynamic_pointer_cast> (other); + + // other must have the same type and value as ours + if (p == nullptr || p->m_comp != m_comp) { return false; } + return true; } private: - T m_functor; //!< the functor + T m_comp; //!< the value of the callback component }; + /** * \ingroup callbackimpl - * CallbackImpl for pointer to member functions - * \tparam OBJ_PTR \deduced Type of the target object, as a pointer. - * \tparam MEM_PTR \deduced Type of the class member function. + * Partial specialization of class CallbackComponent with isComparable equal + * to false. This is required to handle callable objects (such as lambdas and + * objects returned by std::function and std::bind) that do not provide the + * equality operator. Given that these objects cannot be compared and the only + * purpose of the class CallbackComponent is to compare values, no object is + * stored in this specialized class. + * + * \tparam T The type of the callback component. */ -template -class MemPtrCallbackImpl : public CallbackImpl +template +class CallbackComponent : public CallbackComponentBase { public: /** - * Construct from an object pointer and member function pointer + * Constructor * - * \param [in] objPtr The object pointer - * \param [in] memPtr The object class member function + * \param [in] t The value of the callback component */ - MemPtrCallbackImpl (OBJ_PTR const&objPtr, MEM_PTR memPtr) - : m_objPtr (objPtr), m_memPtr (memPtr) + CallbackComponent (const T& t) {} + + /** + * Equality test between functions + * + * \param [in] other CallbackParam Ptr + * \return \c true if we are equal + */ + bool IsEqual (std::shared_ptr other) const + { + return false; + } +}; + +/// Vector of callback components +typedef std::vector> CallbackComponentVector; + +/** + * \ingroup callbackimpl + * CallbackImpl class with varying numbers of argument types + * + * \tparam R \explicit The return type of the Callback. + * \tparam UArgs \explicit The types of any arguments to the Callback. + */ +template +class CallbackImpl : public CallbackImplBase { +public: + + /** + * Constructor. + * + * \param func the callable object + * \param components the callback components (callable object and bound arguments) + */ + CallbackImpl (std::function func, + const CallbackComponentVector& components) + : m_func (func), m_components (components) {} + /** - * Functor with varying numbers of arguments - * @{ + * Get the stored function. + * \return A const reference to the stored function. */ - /** \return Callback value */ - R operator() (void) - { - return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr)(); - } + const std::function& GetFunction (void) const + { return m_func; } + /** - * \param [in] a1 First argument - * \return Callback value + * Get the vector of callback components. + * \return A const reference to the vector of callback components. */ - R operator() (T1 a1) - { - return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr)(a1); - } + const CallbackComponentVector& GetComponents (void) const + { return m_components; } + /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2) - { - return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr)(a1, a2); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3) - { - return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr)(a1, a2, a3); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4) - { - return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr)(a1, a2, a3, a4); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) - { - return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr)(a1, a2, a3, a4, a5); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) - { - return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr)(a1, a2, a3, a4, a5, a6); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7) - { - return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr)(a1, a2, a3, a4, a5, a6, a7); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \param [in] a8 Eighth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8) - { - return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr)(a1, a2, a3, a4, a5, a6, a7, a8); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \param [in] a8 Eighth argument - * \param [in] a9 Ninth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8, T9 a9) - { - return ((CallbackTraits::GetReference (m_objPtr)).*m_memPtr)(a1, a2, a3, a4, a5, a6, a7, a8, a9); - } - /**@}*/ - /** - * Equality test. + * Function call operator. * - * \param [in] other Callback Ptr - * \return \c true if we have the same object and member function + * \param uargs The arguments to the Callback. + * \return Callback value */ + R operator() (UArgs... uargs) const { + return m_func (uargs...); + } + virtual bool IsEqual (Ptr other) const { - MemPtrCallbackImpl const *otherDerived = - dynamic_cast const *> (PeekPointer (other)); + CallbackImpl const *otherDerived = + dynamic_cast const *> (PeekPointer (other)); + if (otherDerived == 0) { return false; } - else if (otherDerived->m_objPtr != m_objPtr - || otherDerived->m_memPtr != m_memPtr) + + // if the two callback implementations are made of a distinct number of + // components, they are different + if (m_components.size () != otherDerived->GetComponents ().size ()) { return false; } + + // the two functions are equal if they compare equal or the shared pointers + // point to the same locations + if (!m_components.at (0)->IsEqual (otherDerived->GetComponents ().at (0)) + && m_components.at (0) != otherDerived->GetComponents ().at (0)) + { + return false; + } + + // check if the remaining components are equal one by one + for (std::size_t i = 1; i < m_components.size (); i++) + { + if (!m_components.at (i)->IsEqual (otherDerived->GetComponents ().at (i))) + { + return false; + } + } + return true; } -private: - OBJ_PTR const m_objPtr; //!< the object pointer - MEM_PTR m_memPtr; //!< the member function pointer -}; + virtual std::string GetTypeid (void) const + { + return DoGetTypeid (); + } + /** \copydoc GetTypeid(). */ + static std::string DoGetTypeid (void) + { + static std::vector vec = { GetCppTypeid (), GetCppTypeid ()... }; -/** - * \ingroup callbackimpl - * CallbackImpl for functors with first argument bound at construction - * \tparam T \explicit Type of the functor. - * \tparam TX \explicit Type of the bound argument. - */ -template -class BoundFunctorCallbackImpl : public CallbackImpl -{ -public: - /** - * Construct from functor and a bound argument - * \tparam FUNCTOR \deduced The actual type of the functor. - * This must be convertible to \pname{T}. - * \tparam ARG \deduced The actual type of the bound argument. - * This must be convertible to type \pname{TX}. - * \param [in] functor The functor - * \param [in] a The argument to bind - */ - template - BoundFunctorCallbackImpl (FUNCTOR functor, ARG a) - : m_functor (functor), m_a (a) - {} - /** - * Functor with varying numbers of arguments - * @{ - */ - /** \return Callback value */ - R operator() (void) - { - return m_functor (m_a); - } - /** - * \param [in] a1 First argument - * \return Callback value - */ - R operator() (T1 a1) - { - return m_functor (m_a,a1); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2) - { - return m_functor (m_a,a1,a2); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3) - { - return m_functor (m_a,a1,a2,a3); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4) - { - return m_functor (m_a,a1,a2,a3,a4); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) - { - return m_functor (m_a,a1,a2,a3,a4,a5); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) - { - return m_functor (m_a,a1,a2,a3,a4,a5,a6); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7) - { - return m_functor (m_a,a1,a2,a3,a4,a5,a6,a7); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \param [in] a8 Eighth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7,T8 a8) - { - return m_functor (m_a,a1,a2,a3,a4,a5,a6,a7,a8); - } - /**@}*/ - /** - * Equality test. - * - * \param [in] other Callback Ptr - * \return \c true if we have the same functor and bound arguments - */ - virtual bool IsEqual (Ptr other) const - { - BoundFunctorCallbackImpl const *otherDerived = - dynamic_cast const *> (PeekPointer (other)); - if (otherDerived == 0) + static std::string id ("CallbackImpl<"); + for (auto& s : vec) { - return false; + id.append (s + ","); } - else if (otherDerived->m_functor != m_functor - || otherDerived->m_a != m_a) + if (id.back () == ',') { - return false; + id.pop_back (); } - return true; + id.push_back ('>'); + + return id; } private: - T m_functor; //!< The functor - typename TypeTraits::ReferencedType m_a; //!< the bound argument + /// Stores the callable object associated with this callback (as a lambda) + std::function m_func; + + /// Stores the original callable object and the bound arguments, if any + std::vector> m_components; }; -/** - * \ingroup callbackimpl - * CallbackImpl for functors with first two arguments bound at construction - * \tparam T \explicit Type of the functor. - * \tparam TX1 \explicit Type of the first bound argument. - * \tparam TX2 \explicit Type of the second bound argument. - */ -template -class TwoBoundFunctorCallbackImpl : public CallbackImpl -{ -public: - /** - * Construct from functor and two arguments - * \tparam FUNCTOR \deduced The actual type of the functor. - * This must be convertible to \pname{T}. - * \tparam ARG1 \deduced The actual type of the first bound argument. - * This must be convertible to type \pname{TX1}. - * \tparam ARG2 \deduced The actual type of the second bound argument. - * This must be convertible to type \pname{TX2}. - * \param [in] functor The functor - * \param [in] arg1 The first argument to bind - * \param [in] arg2 The second argument to bind - */ - template - TwoBoundFunctorCallbackImpl (FUNCTOR functor, ARG1 arg1, ARG2 arg2) - : m_functor (functor), m_a1 (arg1), m_a2 (arg2) - {} - /** - * Functor with varying numbers of arguments - * @{ - */ - /** \return Callback value */ - R operator() (void) - { - return m_functor (m_a1,m_a2); - } - /** - * \param [in] a1 First argument - * \return Callback value - */ - R operator() (T1 a1) - { - return m_functor (m_a1,m_a2,a1); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2) - { - return m_functor (m_a1,m_a2,a1,a2); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3) - { - return m_functor (m_a1,m_a2,a1,a2,a3); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4) - { - return m_functor (m_a1,m_a2,a1,a2,a3,a4); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) - { - return m_functor (m_a1,m_a2,a1,a2,a3,a4,a5); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) - { - return m_functor (m_a1,m_a2,a1,a2,a3,a4,a5,a6); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6,T7 a7) - { - return m_functor (m_a1,m_a2,a1,a2,a3,a4,a5,a6,a7); - } - /**@}*/ - /** - * Equality test. - * - * \param [in] other Callback Ptr - * \return \c true if we have the same functor and bound arguments - */ - virtual bool IsEqual (Ptr other) const - { - TwoBoundFunctorCallbackImpl const *otherDerived = - dynamic_cast const *> (PeekPointer (other)); - if (otherDerived == 0) - { - return false; - } - else if (otherDerived->m_functor != m_functor - || otherDerived->m_a1 != m_a1 || otherDerived->m_a2 != m_a2) - { - return false; - } - return true; - } - -private: - T m_functor; //!< The functor - typename TypeTraits::ReferencedType m_a1; //!< first bound argument - typename TypeTraits::ReferencedType m_a2; //!< second bound argument -}; - -/** - * \ingroup callbackimpl - * CallbackImpl for functors with first three arguments bound at construction - * \tparam T \explicit Type of the functor. - * \tparam TX1 \explicit Type of the first bound argument. - * \tparam TX2 \explicit Type of the second bound argument. - * \tparam TX3 \explicit Type of the third bound argument. - */ -template -class ThreeBoundFunctorCallbackImpl : public CallbackImpl -{ -public: - /** - * Construct from functor and three arguments - * \tparam FUNCTOR \deduced The actual type of the functor. - * This must be convertible to \pname{T}. - * \tparam ARG1 \deduced The actual type of the first bound argument. - * This must be convertible to type \pname{TX1}. - * \tparam ARG2 \deduced The actual type of the second bound argument. - * This must be convertible to type \pname{TX2}. - * \tparam ARG3 \deduced The actual type of the third bound argument. - * This must be convertible to type \pname{TX3}. - * \param [in] functor The functor - * \param [in] arg1 The first argument to bind - * \param [in] arg2 The second argument to bind - * \param [in] arg3 The third argument to bind - */ - template - ThreeBoundFunctorCallbackImpl (FUNCTOR functor, ARG1 arg1, ARG2 arg2, ARG3 arg3) - : m_functor (functor), m_a1 (arg1), m_a2 (arg2), m_a3 (arg3) - {} - /** - * Functor with varying numbers of arguments - * @{ - */ - /** \return Callback value */ - R operator() (void) - { - return m_functor (m_a1,m_a2,m_a3); - } - /** - * \param [in] a1 First argument - * \return Callback value - */ - R operator() (T1 a1) - { - return m_functor (m_a1,m_a2,m_a3,a1); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2) - { - return m_functor (m_a1,m_a2,m_a3,a1,a2); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3) - { - return m_functor (m_a1,m_a2,m_a3,a1,a2,a3); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4) - { - return m_functor (m_a1,m_a2,m_a3,a1,a2,a3,a4); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5) - { - return m_functor (m_a1,m_a2,m_a3,a1,a2,a3,a4,a5); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \return Callback value - */ - R operator() (T1 a1,T2 a2,T3 a3,T4 a4,T5 a5,T6 a6) - { - return m_functor (m_a1,m_a2,m_a3,a1,a2,a3,a4,a5,a6); - } - /**@}*/ - /** - * Equality test. - * - * \param [in] other Callback Ptr - * \return \c true if we have the same functor and bound arguments - */ - virtual bool IsEqual (Ptr other) const - { - ThreeBoundFunctorCallbackImpl const *otherDerived = - dynamic_cast const *> (PeekPointer (other)); - if (otherDerived == 0) - { - return false; - } - else if (otherDerived->m_functor != m_functor - || otherDerived->m_a1 != m_a1 || otherDerived->m_a2 != m_a2 || otherDerived->m_a3 != m_a3) - { - return false; - } - return true; - } - -private: - T m_functor; //!< The functor - typename TypeTraits::ReferencedType m_a1; //!< first bound argument - typename TypeTraits::ReferencedType m_a2; //!< second bound argument - typename TypeTraits::ReferencedType m_a3; //!< third bound argument -}; /** * \ingroup callbackimpl @@ -1213,7 +379,6 @@ protected: * the return type of the callback. * - the remaining (optional) template arguments represent * the type of the subsequent arguments to the callback. - * - up to nine arguments are supported. * * Callback instances are built with the \ref MakeCallback * template functions. Callback instances have POD semantics: @@ -1239,10 +404,6 @@ protected: * - the pimpl idiom: the Callback class is passed around by * value and delegates the crux of the work to its pimpl * pointer. - * - two pimpl implementations which derive from CallbackImpl - * FunctorCallbackImpl can be used with any functor-type - * while MemPtrCallbackImpl can be used with pointers to - * member functions. * - a reference list implementation to implement the Callback's * value semantics. * @@ -1256,116 +417,112 @@ protected: * \see attribute_Callback * * \tparam R \explicit The return type of the Callback. - * The remaining template arguments are the types of any arguments - * to the Callback. + * \tparam UArgs \explicit The types of any arguments to the Callback. */ -template -class Callback : public CallbackBase -{ +template +class Callback : public CallbackBase { public: Callback () {} - /** - * Construct a functor call back, supporting operator() calls - * - * \param [in] functor The functor to run on this callback - * - * \internal - * There are two dummy args below to ensure that this constructor is - * always properly disambiguated by the c++ compiler. - * \tparam FUNCTOR \deduced The actual type of the functor. - */ - template - Callback (FUNCTOR const &functor, bool, bool) - : CallbackBase (Create > (functor)) - {} - - /** - * Construct a member function pointer call back. - * - * \tparam OBJ_PTR \deduced Type of the target object, as a pointer. - * \tparam MEM_PTR \deduced Type of the class member function. - * \param [in] objPtr Pointer to the object - * \param [in] memPtr Pointer to the member function - */ - template - Callback (OBJ_PTR const &objPtr, MEM_PTR memPtr) - : CallbackBase (Create > (objPtr, memPtr)) - {} - /** * Construct from a CallbackImpl pointer * * \param [in] impl The CallbackImpl Ptr */ - Callback (Ptr > const &impl) + Callback (Ptr> const &impl) : CallbackBase (impl) {} /** - * Bind the first arguments + * Construct from another callback and bind some arguments (if any) * - * \tparam T \deduced The type of the bound argument. - * \param [in] a Argument to bind - * \return The bound callback + * \tparam BArgs \deduced The types of the bound arguments + * \param [in] cb The existing callback + * \param [in] bargs The values of the bound arguments */ - template - Callback Bind (T a) + template + Callback (const CallbackBase& cb, BArgs... bargs) { - Ptr > impl = - Ptr > ( - new BoundFunctorCallbackImpl< - Callback, - R,T1,T2,T3,T4,T5,T6,T7,T8,T9> (*this, a), false); - return Callback (impl); + auto cbDerived = static_cast const *> (PeekPointer (cb.GetImpl ())); + + std::function f (cbDerived->GetFunction ()); + + CallbackComponentVector components (cbDerived->GetComponents ()); + components.insert (components.end (), { std::make_shared> (bargs)... }); + + m_impl = Create> ([f,bargs...](UArgs... uargs) -> R + { return f (bargs..., uargs...); }, + components); } /** - * Bind the first two arguments + * Construct from a function and bind some arguments (if any) * - * \tparam TX1 \deduced Type of the first bound argument. - * \tparam TX2 \deduced Type of the second bound argument. - * \param [in] a1 First argument to bind - * \param [in] a2 Second argument to bind - * \return The bound callback + * \tparam T \deduced The type of the function + * \tparam BArgs \deduced The types of the bound arguments + * \param [in] func The function + * \param [in] bargs The values of the bound arguments + * + * \internal + * We leverage SFINAE to have the compiler discard this constructor when the type + * of the first argument is a class derived from CallbackBase (i.e., a Callback). */ - template - Callback TwoBind (TX1 a1, TX2 a2) + template ,int> = 0, + typename... BArgs> + Callback (T func, BArgs... bargs) { - Ptr > impl = - Ptr > ( - new TwoBoundFunctorCallbackImpl< - Callback, - R,T1,T2,T3,T4,T5,T6,T7,T8,T9> (*this, a1, a2), false); - return Callback (impl); + // store the function in a std::function object + std::function f (func); + + // The original function is comparable if it is a function pointer or + // a pointer to a member function or a pointer to a member data. + constexpr bool isComp = std::is_function_v> + || std::is_member_pointer_v; + + CallbackComponentVector components ({ std::make_shared> (func), + std::make_shared> (bargs)... }); + + m_impl = Create> ([f,bargs...](UArgs... uargs) -> R + { return f (bargs..., uargs...); }, + components); } +private: /** - * Bind the first three arguments + * Implementation of the Bind method * - * \tparam TX1 \deduced The actual type of the first bound argument. - * \tparam TX2 \deduced The actual type of the second bound argument. - * \tparam TX3 \deduced The actual type of the third bound argument. - * \param [in] a1 First argument to bind - * \param [in] a2 Second argument to bind - * \param [in] a3 Third argument to bind + * \tparam BoundArgs The types of the arguments to bind + * \param [in] seq A compile-time integer sequence + * \param [in] bargs The values of the arguments to bind + * \return The bound callback + * + * \internal + * The integer sequence is 0..N-1, where N is the number of arguments left unbound. + */ + template + auto BindImpl (std::index_sequence seq, BoundArgs... bargs) + { + return Callback>...> + (*this, bargs...); + } + +public: + + /** + * Bind a variable number of arguments + * + * \tparam BoundArgs \deduced The types of the arguments to bind + * \param [in] bargs The values of the arguments to bind * \return The bound callback */ - template - Callback ThreeBind (TX1 a1, TX2 a2, TX3 a3) + template + auto Bind (BoundArgs... bargs) { - Ptr > impl = - Ptr > ( - new ThreeBoundFunctorCallbackImpl< - Callback, - R,T1,T2,T3,T4,T5,T6,T7,T8,T9> (*this, a1, a2, a3), false); - return Callback (impl); + static_assert (sizeof...(UArgs) > 0); + return BindImpl (std::make_index_sequence{}, + std::forward (bargs)...); } /** @@ -1385,122 +542,13 @@ public: /** * Functor with varying numbers of arguments - * @{ - */ - /** \return Callback value */ - R operator() (void) const - { - return (*(DoPeekImpl ()))(); - } - /** - * \param [in] a1 First argument + * + * \param uargs The arguments to the callback * \return Callback value */ - R operator() (T1 a1) const - { - return (*(DoPeekImpl ()))(a1); + R operator() (UArgs... uargs) const { + return (*(DoPeekImpl ()))(uargs...); } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \return Callback value - */ - R operator() (T1 a1, T2 a2) const - { - return (*(DoPeekImpl ()))(a1,a2); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \return Callback value - */ - R operator() (T1 a1, T2 a2, T3 a3) const - { - return (*(DoPeekImpl ()))(a1,a2,a3); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \return Callback value - */ - R operator() (T1 a1, T2 a2, T3 a3, T4 a4) const - { - return (*(DoPeekImpl ()))(a1,a2,a3,a4); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \return Callback value - */ - R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5) const - { - return (*(DoPeekImpl ()))(a1,a2,a3,a4,a5); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \return Callback value - */ - R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5,T6 a6) const - { - return (*(DoPeekImpl ()))(a1,a2,a3,a4,a5,a6); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \return Callback value - */ - R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5,T6 a6,T7 a7) const - { - return (*(DoPeekImpl ()))(a1,a2,a3,a4,a5,a6,a7); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \param [in] a8 Eighth argument - * \return Callback value - */ - R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5,T6 a6,T7 a7,T8 a8) const - { - return (*(DoPeekImpl ()))(a1,a2,a3,a4,a5,a6,a7,a8); - } - /** - * \param [in] a1 First argument - * \param [in] a2 Second argument - * \param [in] a3 Third argument - * \param [in] a4 Fourth argument - * \param [in] a5 Fifth argument - * \param [in] a6 Sixth argument - * \param [in] a7 Seventh argument - * \param [in] a8 Eighth argument - * \param [in] a9 Ninth argument - * \return Callback value - */ - R operator() (T1 a1, T2 a2, T3 a3, T4 a4,T5 a5,T6 a6,T7 a7,T8 a8, T9 a9) const - { - return (*(DoPeekImpl ()))(a1,a2,a3,a4,a5,a6,a7,a8,a9); - } - /**@}*/ /** * Equality test. @@ -1531,14 +579,24 @@ public: */ bool Assign (const CallbackBase &other) { - return DoAssign (other.GetImpl ()); + auto otherImpl = other.GetImpl (); + if (!DoCheckType (otherImpl)) + { + std::string othTid = otherImpl->GetTypeid (); + std::string myTid = CallbackImpl::DoGetTypeid (); + NS_FATAL_ERROR_CONT ("Incompatible types. (feed to \"c++filt -t\" if needed)" << std::endl << + "got=" << othTid << std::endl << + "expected=" << myTid); + return false; + } + m_impl = const_cast (PeekPointer (otherImpl)); + return true; } private: /** \return The pimpl pointer */ - CallbackImpl * DoPeekImpl (void) const - { - return static_cast *> (PeekPointer (m_impl)); + CallbackImpl *DoPeekImpl (void) const { + return static_cast *> (PeekPointer (m_impl)); } /** * Check for compatible types @@ -1548,8 +606,8 @@ private: */ bool DoCheckType (Ptr other) const { - if (other - && dynamic_cast *> (PeekPointer (other)) != 0) + if (other && + dynamic_cast *> (PeekPointer (other)) != 0) { return true; } @@ -1562,44 +620,21 @@ private: return false; } } - /* Broken: \copydoc Callback::Assign() */ - /** - * Adopt the other's implementation, if type compatible - * - * \param [in] other Callback - * \returns \c true if \pname{other} was type-compatible and could be adopted. - */ - bool DoAssign (Ptr other) - { - if (!DoCheckType (other)) - { - std::string othTid = other->GetTypeid (); - std::string myTid = CallbackImpl::DoGetTypeid (); - NS_FATAL_ERROR_CONT ("Incompatible types. (feed to \"c++filt -t\" if needed)" << std::endl << - "got=" << othTid << std::endl << - "expected=" << myTid); - return false; - } - m_impl = const_cast (PeekPointer (other)); - return true; - } }; /** * Inequality test. * + * \tparam R \explicit The return type of the Callbacks + * \tparam UArgs \explicit The types of any arguments to the Callbacks * \param [in] a Callback * \param [in] b Callback * * \return \c true if the Callbacks are not equal */ -template -bool operator != (Callback a, Callback b) +template +bool operator != (Callback a, Callback b) { return !a.IsEqual (b); } @@ -1614,318 +649,101 @@ bool operator != (Callback a, Callback -Callback MakeCallback (R (T::*memPtr)(Ts...), OBJ objPtr) -{ - return Callback (objPtr, memPtr); +template +Callback MakeCallback (R (T::*memPtr)(Args...), OBJ objPtr) { + return Callback (memPtr, objPtr); } -template -Callback MakeCallback (R (T::*memPtr)(Ts...) const, OBJ objPtr) -{ - return Callback (objPtr, memPtr); + +template +Callback MakeCallback (R (T::*memPtr)(Args...) const, OBJ objPtr) { + return Callback (memPtr, objPtr); } /**@}*/ /** * \ingroup callback + * \tparam R \deduced Return type of the callback function.. + * \tparam Args \deduced Type list of any arguments to the member function. * \param [in] fnPtr Function pointer * \return A wrapper Callback * * Build Callbacks for functions which take varying numbers of arguments * and potentially returning a value. - * - * \tparam R \deduced Return type of the callback function.. - * \tparam Ts \deduced Type list of any arguments to the member function. */ -template -Callback MakeCallback (R (*fnPtr)(Ts...)) -{ - return Callback (fnPtr, true, true); +template +Callback MakeCallback (R (*fnPtr)(Args...)) { + return Callback (fnPtr); } /** * \ingroup callback + * \tparam R \deduced Return type of the callback function.. + * \tparam Args \deduced Type list of any arguments to the member function. * \return A wrapper Callback * * Build null Callbacks which take no arguments, * for varying number of template arguments, * and potentially returning a value. - * + */ +template +Callback MakeNullCallback (void) { + return Callback (); +} + + +/** + * \ingroup makeboundcallback + * @{ + * Make Callbacks with varying number of bound arguments. * \tparam R \deduced Return type of the callback function.. - * \tparam Ts \deduced Type list of any arguments to the member function. + * \tparam Args \deduced Type list of any arguments to the member function. + * \tparam BArgs \deduced Type list of bound arguments. + * \param [in] fnPtr Function pointer + * \param [in] bargs Bound arguments + * \return A bound Callback */ -template -Callback MakeNullCallback (void) +template +auto MakeBoundCallback (R (*fnPtr)(Args...), BArgs... bargs) { - return Callback (); + return Callback (fnPtr).Bind (bargs...); } - /** - * \ingroup makeboundcallback - * @{ - * Make Callbacks with one bound argument. + * \tparam T \deduced Type of the class having the member function. + * \tparam OBJ \deduced Type of the class instance. + * \tparam R \deduced Return type of the callback. + * \tparam Args \deduced Type list of any arguments to the member function. + * \tparam BArgs \deduced Type list of bound arguments. + * \param [in] memPtr Class method member pointer + * \param [in] objPtr Class instance + * \param [in] bargs Bound arguments + * \return A wrapper Callback * - * \tparam R \deduced Return type of the callback - * \tparam TX \deduced Formal type of the first argument to the callback. - * \tparam ARG \deduced Actual type of the bound argument. - * Remaining template parameters are the types of remaining arguments - * to the callback. - * \param [in] fnPtr Function pointer - * \param [in] a1 First bound argument - * \return A bound Callback + * Build Callbacks for class method members which take varying numbers of arguments + * and potentially returning a value. */ -template -Callback MakeBoundCallback (R (*fnPtr)(TX), ARG a1) +template +auto MakeCallback (R (T::*memPtr)(Args...), OBJ objPtr, BArgs... bargs) { - Ptr > impl = - Create > (fnPtr, a1); - return Callback (impl); + return Callback (memPtr, objPtr).Bind (bargs...); } -template -Callback MakeBoundCallback (R (*fnPtr)(TX,T1), ARG a1) + +template +auto MakeCallback (R (T::*memPtr)(Args...) const, OBJ objPtr, BArgs... bargs) { - Ptr > impl = - Create > (fnPtr, a1); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX,T1,T2), ARG a1) -{ - Ptr > impl = - Create > (fnPtr, a1); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX,T1,T2,T3), ARG a1) -{ - Ptr > impl = - Create > (fnPtr, a1); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX,T1,T2,T3,T4), ARG a1) -{ - Ptr > impl = - Create > (fnPtr, a1); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX,T1,T2,T3,T4,T5), ARG a1) -{ - Ptr > impl = - Create > (fnPtr, a1); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX,T1,T2,T3,T4,T5,T6), ARG a1) -{ - Ptr > impl = - Create > (fnPtr, a1); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX,T1,T2,T3,T4,T5,T6,T7), ARG a1) -{ - Ptr > impl = - Create > (fnPtr, a1); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX,T1,T2,T3,T4,T5,T6,T7,T8), ARG a1) -{ - Ptr > impl = - Create > (fnPtr, a1); - return Callback (impl); + return Callback (memPtr, objPtr).Bind (bargs...); } /**@}*/ -/** - * \ingroup makeboundcallback - * @{ - * Make Callbacks with two bound arguments. - * \tparam R \deduced Return type of the callback - * \tparam TX1 \deduced Formal type of the first argument to the callback. - * \tparam TX2 \deduced Formal type of the second argument to the callback. - * \tparam ARG1 \deduced Actual type of the first bound argument. - * \tparam ARG2 \deduced Actual type of the second bound argument. - * Remaining template parameters are the types of remaining arguments - * to the callback. - * \param [in] fnPtr Function pointer - * \param [in] a1 First bound argument - * \param [in] a2 Second bound argument - * \return A bound Callback - */ -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2), ARG1 a1, ARG2 a2) -{ - Ptr > impl = - Create > (fnPtr, a1, a2); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,T1), ARG1 a1, ARG2 a2) -{ - Ptr > impl = - Create > (fnPtr, a1, a2); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,T1,T2), ARG1 a1, ARG2 a2) -{ - Ptr > impl = - Create > (fnPtr, a1, a2); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,T1,T2,T3), ARG1 a1, ARG2 a2) -{ - Ptr > impl = - Create > (fnPtr, a1, a2); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,T1,T2,T3,T4), ARG1 a1, ARG2 a2) -{ - Ptr > impl = - Create > (fnPtr, a1, a2); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,T1,T2,T3,T4,T5), ARG1 a1, ARG2 a2) -{ - Ptr > impl = - Create > (fnPtr, a1, a2); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,T1,T2,T3,T4,T5,T6), ARG1 a1, ARG2 a2) -{ - Ptr > impl = - Create > (fnPtr, a1, a2); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,T1,T2,T3,T4,T5,T6,T7), ARG1 a1, ARG2 a2) -{ - Ptr > impl = - Create > (fnPtr, a1, a2); - return Callback (impl); -} -/**@}*/ - -/** - * \ingroup makeboundcallback - * @{ - * Make Callbacks with three bound arguments. - * \tparam R \deduced Return type of the callback - * \tparam TX1 \deduced Formal type of the first argument to the callback. - * \tparam TX2 \deduced Formal type of the second argument to the callback. - * \tparam TX3 \deduced Formal type of the third argument to the callback. - * \tparam ARG1 \deduced Actual type of the first bound argument. - * \tparam ARG2 \deduced Actual type of the second bound argument. - * \tparam ARG3 \deduced Actual type of the third bound argument. - * Remaining template parameters are the types of remaining arguments - * to the callback. - * \param [in] a1 First bound argument - * \param [in] a2 Second bound argument - * \param [in] a3 Third bound argument - * \param [in] fnPtr Function pointer - * \return A bound Callback - */ -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,TX3), ARG1 a1, ARG2 a2, ARG3 a3) -{ - Ptr > impl = - Create > (fnPtr, a1, a2, a3); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,TX3,T1), ARG1 a1, ARG2 a2, ARG3 a3) -{ - Ptr > impl = - Create > (fnPtr, a1, a2, a3); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,TX3,T1,T2), ARG1 a1, ARG2 a2, ARG3 a3) -{ - Ptr > impl = - Create > (fnPtr, a1, a2, a3); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,TX3,T1,T2,T3), ARG1 a1, ARG2 a2, ARG3 a3) -{ - Ptr > impl = - Create > (fnPtr, a1, a2, a3); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,TX3,T1,T2,T3,T4), ARG1 a1, ARG2 a2, ARG3 a3) -{ - Ptr > impl = - Create > (fnPtr, a1, a2, a3); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,TX3,T1,T2,T3,T4,T5), ARG1 a1, ARG2 a2, ARG3 a3) -{ - Ptr > impl = - Create > (fnPtr, a1, a2, a3); - return Callback (impl); -} -template -Callback MakeBoundCallback (R (*fnPtr)(TX1,TX2,TX3,T1,T2,T3,T4,T5,T6), ARG1 a1, ARG2 a2, ARG3 a3) -{ - Ptr > impl = - Create > (fnPtr, a1, a2, a3); - return Callback (impl); -} -/**@}*/ - - } // namespace ns3 namespace ns3 { diff --git a/src/core/model/unix-fd-reader.cc b/src/core/model/unix-fd-reader.cc index 97be0b44a..d72c8b86e 100644 --- a/src/core/model/unix-fd-reader.cc +++ b/src/core/model/unix-fd-reader.cc @@ -45,7 +45,7 @@ namespace ns3 { NS_LOG_COMPONENT_DEFINE ("FdReader"); FdReader::FdReader () - : m_fd (-1), m_readCallback (0), m_stop (false), + : m_fd (-1), m_stop (false), m_destroyEvent () { NS_LOG_FUNCTION (this); diff --git a/src/core/test/callback-test-suite.cc b/src/core/test/callback-test-suite.cc index 0abbee686..d62924a13 100644 --- a/src/core/test/callback-test-suite.cc +++ b/src/core/test/callback-test-suite.cc @@ -98,6 +98,7 @@ private: static bool gBasicCallbackTest5; static bool gBasicCallbackTest6; static bool gBasicCallbackTest7; +static bool gBasicCallbackTest8; /** @} */ /** @@ -144,6 +145,7 @@ BasicCallbackTestCase::DoSetup (void) gBasicCallbackTest5 = false; gBasicCallbackTest6 = false; gBasicCallbackTest7 = false; + gBasicCallbackTest8 = false; } void @@ -153,7 +155,7 @@ BasicCallbackTestCase::DoRun (void) // Make sure we can declare and compile a Callback pointing to a member // function returning void and execute it. // - Callback target1 (this, &BasicCallbackTestCase::Target1); + Callback target1 (&BasicCallbackTestCase::Target1, this); target1 (); NS_TEST_ASSERT_MSG_EQ (m_test1, true, "Callback did not fire"); @@ -162,7 +164,7 @@ BasicCallbackTestCase::DoRun (void) // function that returns an int and execute it. // Callback target2; - target2 = Callback (this, &BasicCallbackTestCase::Target2); + target2 = Callback (&BasicCallbackTestCase::Target2, this); target2 (); NS_TEST_ASSERT_MSG_EQ (m_test2, true, "Callback did not fire"); @@ -170,7 +172,7 @@ BasicCallbackTestCase::DoRun (void) // Make sure we can declare and compile a Callback pointing to a member // function that returns void, takes a double parameter, and execute it. // - Callback target3 = Callback (this, &BasicCallbackTestCase::Target3); + Callback target3 = Callback (&BasicCallbackTestCase::Target3, this); target3 (0.0); NS_TEST_ASSERT_MSG_EQ (m_test3, true, "Callback did not fire"); @@ -178,7 +180,7 @@ BasicCallbackTestCase::DoRun (void) // Make sure we can declare and compile a Callback pointing to a member // function that returns void, takes two parameters, and execute it. // - Callback target4 = Callback (this, &BasicCallbackTestCase::Target4); + Callback target4 = Callback (&BasicCallbackTestCase::Target4, this); target4 (0.0, 1); NS_TEST_ASSERT_MSG_EQ (m_test4, true, "Callback did not fire"); @@ -189,27 +191,32 @@ BasicCallbackTestCase::DoRun (void) // sure that the constructor is properly disambiguated. If the arguments are // not needed, we just pass in dummy values. // - Callback target5 = Callback (&BasicCallbackTarget5, true, true); + Callback target5 = Callback (&BasicCallbackTarget5); target5 (); NS_TEST_ASSERT_MSG_EQ (gBasicCallbackTest5, true, "Callback did not fire"); // // Make sure we can declare and compile a Callback pointing to a non-member // function that returns void, takes one integer argument and execute it. - // We also need to provide two dummy arguments to the constructor here. // - Callback target6 = Callback (&BasicCallbackTarget6, true, true); + Callback target6 = Callback (&BasicCallbackTarget6); target6 (1); NS_TEST_ASSERT_MSG_EQ (gBasicCallbackTest6, true, "Callback did not fire"); // // Make sure we can declare and compile a Callback pointing to a non-member // function that returns int, takes one integer argument and execute it. - // We also need to provide two dummy arguments to the constructor here. // - Callback target7 = Callback (&BasicCallbackTarget7, true, true); + Callback target7 = Callback (&BasicCallbackTarget7); target7 (1); NS_TEST_ASSERT_MSG_EQ (gBasicCallbackTest7, true, "Callback did not fire"); + + // + // Make sure we can create a callback pointing to a lambda. + // + Callback target8 ([](int p){ gBasicCallbackTest8 = true; return p/2.; }); + target8 (5); + NS_TEST_ASSERT_MSG_EQ (gBasicCallbackTest8, true, "Callback did not fire"); } /** @@ -403,6 +410,19 @@ public: virtual ~MakeBoundCallbackTestCase () {} + /** + * Member function to test the creation of a bound callback pointing to a member function + * + * \param a first argument + * \param b second argument + * \param c third argument + * \return the sum of the arguments + */ + int BoundTarget (int a, int b, int c) + { + return a+b+c; + } + private: virtual void DoRun (void); virtual void DoSetup (void); @@ -679,6 +699,170 @@ MakeBoundCallbackTestCase::DoRun (void) NS_TEST_ASSERT_MSG_EQ (gMakeBoundCallbackTest9b, 3456, "Callback did not fire or binding not correct"); NS_TEST_ASSERT_MSG_EQ (gMakeBoundCallbackTest9c, 4567, "Callback did not fire or binding not correct"); NS_TEST_ASSERT_MSG_EQ (gMakeBoundCallbackTest9d, 5678, "Callback did not fire or binding not correct"); + + // + // Test creating a bound callback pointing to a member function. Also, make sure that + // an argument can be bound to a reference. + // + int b = 1; + Callback target10 = Callback (&MakeBoundCallbackTestCase::BoundTarget, this, std::ref (b), 5, 2); + NS_TEST_ASSERT_MSG_EQ (target10 (), 8, "Bound callback returned an unexpected value"); + b = 3; + NS_TEST_ASSERT_MSG_EQ (target10 (), 10, "Bound callback returned an unexpected value"); +} + + +/** + * \ingroup callback-tests + * + * Test the callback equality implementation. + */ +class CallbackEqualityTestCase : public TestCase +{ +public: + CallbackEqualityTestCase (); + virtual ~CallbackEqualityTestCase () {} + + /** + * Member function used to test equality of callbacks. + * + * \param a first argument + * \param b second argument + * \return the sum of the arguments + */ + int TargetMember (double a, int b) + { + return static_cast (a) + b; + } + +private: + virtual void DoRun (void); + virtual void DoSetup (void); +}; + +/** + * Non-member function used to test equality of callbacks. + * + * \param a first argument + * \param b second argument + * \return the sum of the arguments + */ +int +CallbackEqualityTarget (double a, int b) +{ + return static_cast (a) + b; +} + +CallbackEqualityTestCase::CallbackEqualityTestCase () + : TestCase ("Check Callback equality test") +{ +} + +void +CallbackEqualityTestCase::DoSetup (void) +{ +} + +void +CallbackEqualityTestCase::DoRun (void) +{ + // + // Make sure that two callbacks pointing to the same member function + // compare equal. + // + Callback target1a (&CallbackEqualityTestCase::TargetMember, this); + Callback target1b = MakeCallback (&CallbackEqualityTestCase::TargetMember, this); + NS_TEST_ASSERT_MSG_EQ (target1a.IsEqual (target1b), true, "Equality test failed"); + + // + // Make sure that two callbacks pointing to the same member function + // compare equal, after binding the first argument. + // + Callback target2a (&CallbackEqualityTestCase::TargetMember, this, 1.5); + Callback target2b = target1b.Bind (1.5); + NS_TEST_ASSERT_MSG_EQ (target2a.IsEqual (target2b), true, "Equality test failed"); + + // + // Make sure that two callbacks pointing to the same member function + // compare equal, after binding the first two arguments. + // + Callback target3a (target2a, 2); + Callback target3b = target1b.Bind (1.5, 2); + NS_TEST_ASSERT_MSG_EQ (target3a.IsEqual (target3b), true, "Equality test failed"); + + // + // Make sure that two callbacks pointing to the same member function do + // not compare equal if they are bound to different arguments. + // + Callback target3c = target1b.Bind (1.5, 3); + NS_TEST_ASSERT_MSG_EQ (target3c.IsEqual (target3b), false, "Equality test failed"); + + // + // Make sure that two callbacks pointing to the same non-member function + // compare equal. + // + Callback target4a (&CallbackEqualityTarget); + Callback target4b = MakeCallback (&CallbackEqualityTarget); + NS_TEST_ASSERT_MSG_EQ (target4a.IsEqual (target4b), true, "Equality test failed"); + + // + // Make sure that two callbacks pointing to the same non-member function + // compare equal, after binding the first argument. + // + Callback target5a (&CallbackEqualityTarget, 1.5); + Callback target5b = target4b.Bind (1.5); + NS_TEST_ASSERT_MSG_EQ (target5a.IsEqual (target5b), true, "Equality test failed"); + + // + // Make sure that two callbacks pointing to the same non-member function + // compare equal, after binding the first two arguments. + // + Callback target6a (target5a, 2); + Callback target6b = target4b.Bind (1.5, 2); + NS_TEST_ASSERT_MSG_EQ (target6a.IsEqual (target6b), true, "Equality test failed"); + + // + // Make sure that two callbacks pointing to the same non-member function do + // not compare equal if they are bound to different arguments. + // + Callback target6c = target4b.Bind (1.5, 3); + NS_TEST_ASSERT_MSG_EQ (target6c.IsEqual (target6b), false, "Equality test failed"); + + // + // Check that we cannot compare lambdas. + // + Callback target7a ([](int p, double d){ return d + p/2.; }); + Callback target7b ([](int p, double d){ return d + p/2.; }); + NS_TEST_ASSERT_MSG_EQ (target7a.IsEqual (target7b), false, "Compared lambdas?"); + + // + // Make sure that a callback pointing to a lambda and a copy of it compare equal. + // + Callback target7c (target7b); + NS_TEST_ASSERT_MSG_EQ (target7c.IsEqual (target7b), true, "Equality test failed"); + + // + // Make sure that a callback pointing to a lambda and a copy of it compare equal, + // after binding the first argument. + // + Callback target8b = target7b.Bind (1); + Callback target8c (target7c, 1); + NS_TEST_ASSERT_MSG_EQ (target8b.IsEqual (target8c), true, "Equality test failed"); + + // + // Make sure that a callback pointing to a lambda and a copy of it compare equal, + // after binding the first two arguments. + // + Callback target9b = target8b.Bind (2); + Callback target9c (target8c, 2); + NS_TEST_ASSERT_MSG_EQ (target9b.IsEqual (target9c), true, "Equality test failed"); + + // + // Make sure that a callback pointing to a lambda and a copy of it do not compare + // equal if they are bound to different arguments. + // + Callback target9d = target8b.Bind (4); + NS_TEST_ASSERT_MSG_EQ (target9d.IsEqual (target9c), false, "Equality test failed"); } /** @@ -935,6 +1119,7 @@ CallbackTestSuite::CallbackTestSuite () AddTestCase (new BasicCallbackTestCase, TestCase::QUICK); AddTestCase (new MakeCallbackTestCase, TestCase::QUICK); AddTestCase (new MakeBoundCallbackTestCase, TestCase::QUICK); + AddTestCase (new CallbackEqualityTestCase, TestCase::QUICK); AddTestCase (new NullifyCallbackTestCase, TestCase::QUICK); AddTestCase (new MakeCallbackTemplatesTestCase, TestCase::QUICK); } diff --git a/src/core/test/traced-callback-test-suite.cc b/src/core/test/traced-callback-test-suite.cc index ac3a1c3d4..9a2855e2b 100644 --- a/src/core/test/traced-callback-test-suite.cc +++ b/src/core/test/traced-callback-test-suite.cc @@ -53,13 +53,8 @@ private: * \param b Second parameter. */ void CbOne (uint8_t a, double b); - /** - * Second callback. - * \param a First parameter. - * \param b Second parameter. - */ - void CbTwo (uint8_t a, double b); + CallbackBase m_cbTwo; //!< second callback bool m_one; //!< Variable set by the first callback. bool m_two; //!< Variable set by the second callback. }; @@ -74,15 +69,18 @@ BasicTracedCallbackTestCase::CbOne ([[maybe_unused]] uint8_t a, [[maybe_unused]] m_one = true; } -void -BasicTracedCallbackTestCase::CbTwo ([[maybe_unused]] uint8_t a, [[maybe_unused]] double b) -{ - m_two = true; -} void BasicTracedCallbackTestCase::DoRun (void) { + // + // Disconnecting callbacks from a traced callback is based on the ability to + // compare callbacks. Given that lambdas cannot be compared, a callback + // pointing to a lambda needs to be stored to allow it to be disconnected + // later. Here we check that it is enough to store the callback as a CallbackBase. + // + m_cbTwo = Callback ([this](uint8_t, double){ m_two = true; }); + // // Create a traced callback and connect it up to our target methods. All that // these methods do is to set corresponding member variables m_one and m_two. @@ -95,7 +93,7 @@ BasicTracedCallbackTestCase::DoRun (void) // to true. // trace.ConnectWithoutContext (MakeCallback (&BasicTracedCallbackTestCase::CbOne, this)); - trace.ConnectWithoutContext (MakeCallback (&BasicTracedCallbackTestCase::CbTwo, this)); + trace.ConnectWithoutContext (m_cbTwo); m_one = false; m_two = false; trace (1, 2); @@ -115,7 +113,7 @@ BasicTracedCallbackTestCase::DoRun (void) // // If we now disconnect callback two then neither callback should be called. // - trace.DisconnectWithoutContext (MakeCallback (&BasicTracedCallbackTestCase::CbTwo, this)); + trace.DisconnectWithoutContext (m_cbTwo); m_one = false; m_two = false; trace (1, 2); @@ -126,7 +124,7 @@ BasicTracedCallbackTestCase::DoRun (void) // If we connect them back up, then both callbacks should be called. // trace.ConnectWithoutContext (MakeCallback (&BasicTracedCallbackTestCase::CbOne, this)); - trace.ConnectWithoutContext (MakeCallback (&BasicTracedCallbackTestCase::CbTwo, this)); + trace.ConnectWithoutContext (m_cbTwo); m_one = false; m_two = false; trace (1, 2); diff --git a/src/internet/model/icmpv4-l4-protocol.cc b/src/internet/model/icmpv4-l4-protocol.cc index 70927333a..ab6c39522 100644 --- a/src/internet/model/icmpv4-l4-protocol.cc +++ b/src/internet/model/icmpv4-l4-protocol.cc @@ -324,7 +324,7 @@ IpL4Protocol::DownTargetCallback6 Icmpv4L4Protocol::GetDownTarget6 (void) const { NS_LOG_FUNCTION (this); - return (IpL4Protocol::DownTargetCallback6)NULL; + return IpL4Protocol::DownTargetCallback6 (); } } // namespace ns3 diff --git a/src/internet/model/icmpv6-l4-protocol.cc b/src/internet/model/icmpv6-l4-protocol.cc index fcfadb563..0977f2fe1 100644 --- a/src/internet/model/icmpv6-l4-protocol.cc +++ b/src/internet/model/icmpv6-l4-protocol.cc @@ -1606,7 +1606,7 @@ IpL4Protocol::DownTargetCallback Icmpv6L4Protocol::GetDownTarget (void) const { NS_LOG_FUNCTION (this); - return (IpL4Protocol::DownTargetCallback)NULL; + return IpL4Protocol::DownTargetCallback (); } IpL4Protocol::DownTargetCallback6 diff --git a/src/spectrum/model/matrix-based-channel-model.h b/src/spectrum/model/matrix-based-channel-model.h index d4e9379bc..82c7476f9 100644 --- a/src/spectrum/model/matrix-based-channel-model.h +++ b/src/spectrum/model/matrix-based-channel-model.h @@ -22,7 +22,7 @@ #ifndef MATRIX_BASED_CHANNEL_H #define MATRIX_BASED_CHANNEL_H -#include +// #include #include #include #include diff --git a/src/wifi/test/wifi-primary-channels-test.cc b/src/wifi/test/wifi-primary-channels-test.cc index cbd440ec6..9961a05db 100644 --- a/src/wifi/test/wifi-primary-channels-test.cc +++ b/src/wifi/test/wifi-primary-channels-test.cc @@ -474,7 +474,7 @@ WifiPrimaryChannelsTest::DoRun (void) auto dev = DynamicCast (m_staDevices[bss].Get (i)); Simulator::Schedule (m_time, &WifiPhy::SetReceiveOkCallback, dev->GetPhy (), MakeCallback (&WifiPrimaryChannelsTest::ReceiveDl, this) - .TwoBind (bss, i)); + .Bind (bss, i)); } auto dev = DynamicCast (m_apDevices.Get (bss)); Simulator::Schedule (m_time, &WifiPhy::SetReceiveOkCallback, dev->GetPhy (),