2016-05-13 19:54:46 +00:00
/* mbed Microcontroller Library
2019-06-27 08:49:22 +00:00
* Copyright ( c ) 2006 - 2019 ARM Limited
2018-11-09 11:31:20 +00:00
* SPDX - License - Identifier : Apache - 2.0
2016-05-13 19:54:46 +00:00
*
* Licensed under the Apache License , Version 2.0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
# ifndef MBED_CALLBACK_H
# define MBED_CALLBACK_H
2019-07-02 14:27:15 +00:00
# include <cstring>
# include <mstd_cstddef>
2016-05-13 19:54:46 +00:00
# include <stdint.h>
2019-07-02 14:27:15 +00:00
# include <mstd_new>
2016-10-01 07:11:36 +00:00
# include "platform/mbed_assert.h"
2017-01-27 11:10:28 +00:00
# include "platform/mbed_toolchain.h"
2019-07-02 14:27:15 +00:00
# include <mstd_type_traits>
# include <mstd_functional>
// Controlling switches from config:
// MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL - support storing non-trivial function objects
// MBED_CONF_PLATFORM_CALLBACK_COMPARABLE - support memcmp comparing stored objects (requires zero padding)
2016-05-13 19:54:46 +00:00
2020-05-25 12:23:20 +00:00
# ifdef __ICCARM__
/* Force platform.callback-nontrivial for IAR */
# undef MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
# define MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL 1
# endif
2016-05-13 19:54:46 +00:00
namespace mbed {
2019-06-27 08:49:22 +00:00
/** \addtogroup platform-public-api */
2017-10-24 15:05:45 +00:00
/** @{*/
/**
* \ defgroup platform_Callback Callback class
* @ {
*/
2016-05-13 19:54:46 +00:00
/** Callback class based on template specialization
2016-06-08 12:52:14 +00:00
*
2017-04-04 19:21:53 +00:00
* @ note Synchronization level : Not protected
2016-05-13 19:54:46 +00:00
*/
2019-07-02 14:27:15 +00:00
template < typename Signature >
2016-05-13 19:54:46 +00:00
class Callback ;
2016-09-27 21:03:00 +00:00
namespace detail {
2019-07-02 14:27:15 +00:00
/* Convert pointer-to-member type to member type */
template < typename T >
struct member_type { } ;
template < typename M , class C >
struct member_type < M C : : * > : mstd : : type_identity < M > { } ;
template < typename T >
using member_type_t = typename member_type < T > : : type ;
/* Remove cv-qualifiers and lvalue ref-qualifiers */
/* Not rvalue - we store the function object, so are always going to call it on an lvalue */
template < typename T >
struct unqualify_fn { } ;
// *INDENT-OFF*
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) & > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) const > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) const & > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) volatile > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) volatile & > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) const volatile > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) const volatile & > : mstd : : type_identity < R ( Args . . . ) > { } ;
# if __cplusplus >=201703 || __cpp_noexcept_function_type >= 201510
/* We have to spell out all c/v/ref/noexcept versions here, as specialization needs exact type match */
/* Compare to callback() and deduction guides, where dropping the noexcept is a permitted conversion */
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) noexcept > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) & noexcept > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) const noexcept > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) const & noexcept > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) volatile noexcept > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) volatile & noexcept > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) const volatile noexcept > : mstd : : type_identity < R ( Args . . . ) > { } ;
template < typename R , typename . . . Args >
struct unqualify_fn < R ( Args . . . ) const volatile & noexcept > : mstd : : type_identity < R ( Args . . . ) > { } ;
# endif
2016-09-27 21:03:00 +00:00
2019-07-02 14:27:15 +00:00
template < typename T >
using unqualify_fn_t = typename unqualify_fn < T > : : type ;
2016-09-27 21:03:00 +00:00
2019-07-02 14:27:15 +00:00
template < typename R , typename F , typename . . . Args , typename std : : enable_if_t < ! std : : is_void < R > : : value , int > = 0 >
R invoke_r ( F & & f , Args & & . . . args )
{
return mstd : : invoke ( std : : forward < F > ( f ) , std : : forward < Args > ( args ) . . . ) ;
2016-09-27 21:03:00 +00:00
}
2019-07-02 14:27:15 +00:00
template < typename R , typename F , typename . . . Args , typename std : : enable_if_t < std : : is_void < R > : : value , int > = 0 >
R invoke_r ( F & & f , Args & & . . . args )
{
mstd : : invoke ( std : : forward < F > ( f ) , std : : forward < Args > ( args ) . . . ) ;
}
2017-04-28 21:02:36 +00:00
2019-07-02 14:27:15 +00:00
template < typename F >
struct can_null_check :
mstd : : disjunction <
std : : is_function < std : : remove_pointer_t < F > > ,
std : : is_member_pointer < F >
> {
} ;
// *INDENT-ON*
struct [ [ gnu : : may_alias ] ] CallbackBase {
// Storage is sufficient to hold at least a pointer to member
// function, and an object pointer.
struct _model_function_object {
struct _class ;
void ( _class : : * _methodfunc ) ( int ) ;
void * obj ;
} ;
/* Notes on the [[gnu::may_alias]] attribute here.
*
* The CallbackBase : : Store is subject to aliasing problems if ever copied via a trivial copy .
* This issue is described here :
*
* https : //answers.launchpad.net/gcc-arm-embedded/+question/686870/+index
* http : //www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0593r5.html
*
* The paper p0593 proposes to solve the problem via a language Defect Report , which would make this
* code valid - it would become legal to copy a trivial object into char array storage . ( But not
* aligned_storage_t , as of version 5 - I ' ve suggested a revision ) .
*
* Real - life problems have only been seen in GCC when the code used aligned_storage_t .
*
* The libstdc + + implementation of std : : function uses the [ [ gnu : : may_alias ] ] attribute itself to avoid
* problems when it swaps locally - stored functors ; we need it for copy - assignment too .
*
* It appears [ [ gnu : : may_alias ] ] doesn ' t work through composition - it ' s not sufficent to mark just the
* ` Store ` type , we have to mark the whole ` Callback ` if we ' re going to let the compiler
* implicitly define the trivial copy for it . This potentially could lead to an issue if a ` Callback `
* was used in a trivially - copyable type itself , but this seems an unlikely use case . The p0593r5
* change would , if correctly implemented , work in composition .
*
* Although , to further increase the confusion , it appears that using a character array does work
* fine without may_alias , while aligned_storage_t does not . I ' ve seen a suggestion that GCC 8
* may have implicit " may_alias " on character arrays , rendering the attribute in std : : function
* and here redundant on current GCC :
*
* https : //gcc.gnu.org/ml/gcc-help/2017-06/msg00102.html
*
* For maximum safety , this version now avoids aligned_storage_t , and also has the possibly - redundant
* attribute at each level .
*
* C + + 17 says that implementations ignore unrecognized attributes , and IAR + clang comply with this
* even in C + + 14 mode , so we add [ [ gnu : : may_alias ] ] unconditionally .
2016-05-13 19:54:46 +00:00
*/
2019-07-02 14:27:15 +00:00
struct alignas ( _model_function_object ) [ [ gnu : : may_alias ] ] Store {
char data [ sizeof ( _model_function_object ) ] ;
} ;
Store _storage ;
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
// Dynamically dispatched operations
const struct ops {
void ( * call ) ( ) ; // type-erased function pointer
void ( * copy ) ( Store & , const Store & ) ;
void ( * dtor ) ( Store & ) ;
} * _ops ;
// Control
using Control = const ops * ;
// Construct as empty
CallbackBase ( std : : nullptr_t ) noexcept : _ops ( nullptr ) { }
# else
void ( * _call ) ( ) ; // type-erased function pointer
using Control = void ( * ) ( ) ;
// Construct as empty
CallbackBase ( std : : nullptr_t ) noexcept : _call ( nullptr ) { }
# endif
// Default constructor - no initialization
CallbackBase ( ) = default ;
Control & control ( )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
return _ops ;
# else
return _call ;
# endif
}
const Control & control ( ) const
{
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
return _ops ;
# else
return _call ;
# endif
}
auto call_fn ( ) const
{
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
return _ops - > call ;
# else
return _call ;
# endif
}
// Clear to empty - does not destroy
void clear ( ) noexcept
{
// For copy efficiency we only zero out the operation pointer
// Therefore storage is undefined when we are empty.
// Callback-to-Callback comparison operator has to deal with this,
// but such comparisons are rare. Comparisons to empty are efficient.
control ( ) = nullptr ;
}
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
// Copy from another CallbackBase - assumes we are uninitialised
void copy ( const CallbackBase & other )
{
_ops = other . _ops ;
if ( _ops ) {
_ops - > copy ( _storage , other . _storage ) ;
2016-09-27 18:27:17 +00:00
}
}
2019-07-02 14:27:15 +00:00
# else
void swap ( CallbackBase & other ) noexcept
{
std : : swap ( _storage , other . _storage ) ;
std : : swap ( _call , other . _call ) ;
}
# endif
2016-09-27 18:27:17 +00:00
2019-07-02 14:27:15 +00:00
// Destroy anything we hold - does not reset, so we are in undefined state afterwards.
// Must be followed by copy, move, reset, or destruction of the CallbackBase
void destroy ( )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
if ( _ops ) {
_ops - > dtor ( _storage ) ;
2016-09-27 18:27:17 +00:00
}
2019-07-02 14:27:15 +00:00
# endif
Added support for cv-qualifiers in Callback class
Additionally, the following changes were don to avoid combinatorial
explosion in function overloads as a result of adding cv-qualifiers:
- Added convenience function for inferred type
- Deprecated callback overloads qhere cv-qualifiers are not scalable
Supported overloads:
callback(void (*f)(A...));
callback(const Callback<R(A...)> &);
callback(T *t, void (*f)(T*, A...));
callback(const T *t, void (*f)(const T*, A...));
callback(volatile T *t, void (*f)(volatile T*, A...));
callback(const volatile T *t, void (*f)(const volatile T*, A...));
callback(T *t, void (T::*f)(A...));
callback(const T *t, void (T::*f)(A...) const);
callback(volatile T *t, void (T::*f)(A...) volatile);
callback(const volatile T *t, void (T::*f)(A...) const volatile);
2016-08-18 18:28:57 +00:00
}
2019-07-02 14:27:15 +00:00
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
// Copy construct F into storage
template < typename F >
static void target_copy ( Store & d , const Store & p )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
const F & f = reinterpret_cast < const F & > ( p ) ;
new ( & d ) F ( f ) ;
2016-09-23 08:29:14 +00:00
}
2019-07-02 14:27:15 +00:00
// Destroy F in storage
template < typename F >
static void target_dtor ( Store & p )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
F & f = reinterpret_cast < F & > ( p ) ;
f . ~ F ( ) ;
2016-09-23 08:29:14 +00:00
}
2019-07-02 14:27:15 +00:00
// Trivial copy construction into storage
static void trivial_target_copy ( Store & d , const Store & p ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
std : : memcpy ( & d , & p , sizeof d ) ;
2016-09-23 08:29:14 +00:00
}
2019-07-02 14:27:15 +00:00
// Trivial destruction in storage
static void trivial_target_dtor ( Store & p ) noexcept
2018-06-27 14:09:15 +00:00
{
2016-09-23 08:29:14 +00:00
}
2019-07-02 14:27:15 +00:00
# endif
} ;
2016-09-23 08:29:14 +00:00
2019-07-02 14:27:15 +00:00
}
/** Callback class based on template specialization
*
* @ note Synchronization level : Not protected
*/
template < typename R , typename . . . ArgTs >
class Callback < R ( ArgTs . . . ) > : private detail : : CallbackBase {
public :
using result_type = R ;
/** Create an empty Callback
2016-09-23 08:29:14 +00:00
*/
2019-07-02 14:27:15 +00:00
Callback ( ) noexcept : CallbackBase ( nullptr ) { }
/** Create an empty Callback
*/
Callback ( std : : nullptr_t ) noexcept : Callback ( ) { }
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
/** Copy a Callback
* @ param other The Callback to copy
*/
Callback ( const Callback & other ) : CallbackBase ( )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
copy ( other ) ;
2016-09-23 08:29:14 +00:00
}
2019-07-02 14:27:15 +00:00
/** Move a Callback
* @ param other The Callback to move
2016-09-23 08:29:14 +00:00
*/
2019-07-02 14:27:15 +00:00
Callback ( Callback & & other ) : CallbackBase ( )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
// Move constructor exists to ensure that it gets selected
// in preference to the universal constructor form.
copy ( other ) ;
2016-09-23 08:29:14 +00:00
}
2019-07-02 14:27:15 +00:00
# else // MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
Callback ( const Callback & other ) = default ;
Callback ( Callback & & other ) = default ;
# endif // MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
2016-09-23 08:29:14 +00:00
2019-07-02 14:27:15 +00:00
/** Create a Callback with a member function
* @ param obj Pointer to object to invoke member function on
* @ param method Member function to attach
2016-09-23 08:29:14 +00:00
*/
2019-07-02 14:27:15 +00:00
template < typename Obj , typename Method , typename std : : enable_if_t < mstd : : is_invocable_r < R , Method , Obj , ArgTs . . . > : : value , int > = 0 >
Callback ( Obj obj , Method method ) : CallbackBase ( )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
generate ( [ obj , method ] ( ArgTs . . . args ) {
return detail : : invoke_r < R > ( method , obj , std : : forward < ArgTs > ( args ) . . . ) ;
} ) ;
2016-09-23 08:29:14 +00:00
}
/** Create a Callback with a static function and bound pointer
* @ param func Static function to attach
2018-06-27 14:09:15 +00:00
* @ param arg Pointer argument to function
2016-09-23 08:29:14 +00:00
*/
2019-07-02 14:27:15 +00:00
template < typename Fn , typename BoundArg , typename std : : enable_if_t < mstd : : is_invocable_r < R , Fn , BoundArg , ArgTs . . . > : : value , int > = 0 >
Callback ( Fn func , BoundArg arg ) : CallbackBase ( )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
generate ( [ func , arg ] ( ArgTs . . . args ) {
return detail : : invoke_r < R > ( func , arg , std : : forward < ArgTs > ( args ) . . . ) ;
} ) ;
2016-09-23 08:29:14 +00:00
}
2019-07-02 14:27:15 +00:00
// *INDENT-OFF*
2016-09-27 21:03:00 +00:00
/** Create a Callback with a function object
2017-04-26 23:41:02 +00:00
* @ param f Function object to attach
2019-07-02 14:27:15 +00:00
* @ note The function object is limited to a a few words of storage
2016-09-27 21:03:00 +00:00
*/
2019-07-02 14:27:15 +00:00
template < typename F ,
typename std : : enable_if_t <
! detail : : can_null_check < F > : : value & &
mstd : : is_invocable_r < R , F , ArgTs . . . > : : value , int > = 0 >
Callback ( F f ) : CallbackBase ( )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
static_assert ( std : : is_copy_constructible < F > : : value , " Callback F must be CopyConstructible " ) ;
generate ( std : : move ( f ) ) ;
2016-09-27 21:03:00 +00:00
}
2019-07-02 14:27:15 +00:00
/** Create a Callback with a function pointer
* @ param f Function pointer to attach
2016-09-27 21:03:00 +00:00
*/
2019-07-02 14:27:15 +00:00
template < typename F ,
typename std : : enable_if_t <
detail : : can_null_check < F > : : value & &
mstd : : is_invocable_r < R , F , ArgTs . . . > : : value , int > = 0 >
Callback ( F f ) : CallbackBase ( )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
static_assert ( std : : is_copy_constructible < F > : : value , " Callback F must be CopyConstructible " ) ;
if ( ! f ) {
clear ( ) ;
} else {
generate ( std : : move ( f ) ) ;
}
2016-09-27 21:03:00 +00:00
}
2019-07-02 14:27:15 +00:00
// *INDENT-ON*
2016-09-27 21:03:00 +00:00
2019-07-02 14:27:15 +00:00
/** Destroy a callback
2016-09-27 21:03:00 +00:00
*/
2019-07-02 14:27:15 +00:00
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
~ Callback ( )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
destroy ( ) ;
2016-09-27 21:03:00 +00:00
}
2019-07-02 14:27:15 +00:00
# else
~ Callback ( ) = default ;
# endif
2016-09-27 21:03:00 +00:00
2019-07-02 14:27:15 +00:00
/** Swap a callback
2016-09-27 21:03:00 +00:00
*/
2019-07-02 14:27:15 +00:00
void swap ( Callback & that ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
if ( this ! = & that ) {
Callback temp ( std : : move ( * this ) ) ;
* this = std : : move ( that ) ;
that = std : : move ( temp ) ;
}
# else
CallbackBase : : swap ( that ) ;
# endif
2016-09-23 08:29:14 +00:00
}
2019-07-02 14:27:15 +00:00
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
/** Assign a callback
2016-09-27 18:27:17 +00:00
*/
2019-07-02 14:27:15 +00:00
Callback & operator = ( const Callback & that )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
// C++ standard says to use swap, but that's overkill with no exceptions
// Callback(f).swap(*this);
if ( this ! = & that ) {
destroy ( ) ;
copy ( that ) ;
2016-09-27 18:27:17 +00:00
}
2019-07-02 14:27:15 +00:00
return * this ;
2016-05-13 19:54:46 +00:00
}
2016-09-27 18:27:17 +00:00
/** Assign a callback
*/
2019-07-02 14:27:15 +00:00
Callback & operator = ( Callback & & that )
2018-06-27 14:09:15 +00:00
{
2016-09-27 18:27:17 +00:00
if ( this ! = & that ) {
2019-07-02 14:27:15 +00:00
destroy ( ) ;
copy ( that ) ;
2016-09-27 18:27:17 +00:00
}
return * this ;
2016-05-13 19:54:46 +00:00
}
2019-07-02 14:27:15 +00:00
# else // MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
Callback & operator = ( const Callback & that ) = default ;
Callback & operator = ( Callback & & that ) = default ;
# endif // MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
/** Assign a callback
*/
// C++ std::function lacks the is_same restriction here, which would mean non-const lvalue references hit this,
// rather than the normal copy assignment (`F &&` is a better match for `Callback &` than `const Callback &`).
// Wouldn't matter if both used the swap form, but having cut it down, for code size want to ensure we don't use this
// instead of copy assignment. (If nontrivial disabled, definitely want to use the default copy assignment, and
// if nontrivial enabled, we know this doesn't handle self-assignment).
// *INDENT-OFF*
template < typename F ,
typename = std : : enable_if_t <
mstd : : is_invocable_r < R , F , ArgTs . . . > : : value & &
! mstd : : is_same < mstd : : remove_cvref_t < F > , Callback > : : value > >
Callback & operator = ( F & & f )
{
// C++ standard says to use swap, but that's overkill with no exceptions
// Callback(std::forward<F>(that)).swap(*this);
this - > ~ Callback ( ) ;
new ( this ) Callback ( std : : forward < F > ( f ) ) ;
return * this ;
}
// *INDENT-ON*
template < typename F >
Callback & operator = ( std : : reference_wrapper < F > f ) noexcept
{
// C++ standard says to use swap, but that's overkill with no exceptions
// Callback(f).swap(*this);
this - > ~ Callback ( ) ;
new ( this ) Callback ( f ) ;
return * this ;
}
/** Empty a callback
*/
Callback & operator = ( std : : nullptr_t ) noexcept
{
destroy ( ) ;
clear ( ) ;
return * this ;
}
2016-05-13 19:54:46 +00:00
2016-09-23 08:29:14 +00:00
/** Call the attached function
2016-05-13 19:54:46 +00:00
*/
2019-06-24 10:06:37 +00:00
R call ( ArgTs . . . args ) const
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
MBED_ASSERT ( bool ( * this ) ) ;
auto op_call = reinterpret_cast < call_type * > ( call_fn ( ) ) ;
return op_call ( this , args . . . ) ;
2016-05-13 19:54:46 +00:00
}
2016-09-23 08:29:14 +00:00
/** Call the attached function
2016-08-19 20:49:49 +00:00
*/
2019-06-24 10:06:37 +00:00
R operator ( ) ( ArgTs . . . args ) const
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return call ( args . . . ) ;
2016-09-23 08:29:14 +00:00
}
2016-05-13 19:54:46 +00:00
2019-07-02 14:27:15 +00:00
/** Test if function has been assigned
2016-05-13 19:54:46 +00:00
*/
2019-07-02 14:27:15 +00:00
explicit operator bool ( ) const noexcept
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
return control ( ) ;
2016-05-13 19:54:46 +00:00
}
2019-07-02 14:27:15 +00:00
# if MBED_CONF_PLATFORM_CALLBACK_COMPARABLE
2016-08-19 20:49:49 +00:00
/** Test for equality
2019-07-02 14:27:15 +00:00
*
* @ note This only compares stored objects byte - wise using memcmp
* after checking that they ' re the same type . It does * not * use
* any equality operator defined for the class .
*
* @ note This is an extension compared to std : : function , and supporting
* it requires extra code even if the comparison is never used .
* Avoid using this operator if possible , so that the option
* ` platform . callback - comparable ` can be turned off to save ROM .
*/
friend bool operator = = ( const Callback & l , const Callback & r ) noexcept
{
if ( l . control ( ) ! = r . control ( ) ) {
/* Type of stored object differs */
return false ;
}
if ( ! l ) {
/* Both must be empty, as we checked the types match. Do not
* check storage in this case - this simplifies clear ( ) , and
* clears are far more common than callback comparison .
*/
return true ;
}
return memcmp ( & l . _storage , & r . _storage , sizeof ( Store ) ) = = 0 ;
}
# endif
/** Test for emptiness
*/
friend bool operator = = ( const Callback & f , std : : nullptr_t ) noexcept
{
return ! f ;
}
/** Test for emptiness
2016-08-19 20:49:49 +00:00
*/
2019-07-02 14:27:15 +00:00
friend bool operator = = ( std : : nullptr_t , const Callback & f ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
return ! f ;
2016-08-19 20:49:49 +00:00
}
2019-07-02 14:27:15 +00:00
# if MBED_CONF_PLATFORM_CALLBACK_COMPARABLE
2016-08-19 20:49:49 +00:00
/** Test for inequality
2019-07-02 14:27:15 +00:00
*
* @ see operator = = ( const Callback & l , const Callback & r )
2016-08-19 20:49:49 +00:00
*/
2019-07-02 14:27:15 +00:00
friend bool operator ! = ( const Callback & l , const Callback & r ) noexcept
2018-06-27 14:09:15 +00:00
{
2016-08-19 20:49:49 +00:00
return ! ( l = = r ) ;
}
2019-07-02 14:27:15 +00:00
# endif
/** Test for non-emptiness
*/
friend bool operator ! = ( const Callback & f , std : : nullptr_t ) noexcept
{
return bool ( f ) ;
}
/** Test for non-emptiness
*/
friend bool operator ! = ( std : : nullptr_t , const Callback & f ) noexcept
{
return bool ( f ) ;
}
2016-08-19 20:49:49 +00:00
2016-05-13 19:54:46 +00:00
/** Static thunk for passing as C-style function
* @ param func Callback to call passed as void pointer
2019-06-24 10:06:37 +00:00
* @ param args Arguments to be called with function func
2018-06-27 14:09:15 +00:00
* @ return the value as determined by func which is of
2018-10-17 21:49:38 +00:00
* type and determined by the signature of func
2016-05-13 19:54:46 +00:00
*/
2019-06-24 10:06:37 +00:00
static R thunk ( void * func , ArgTs . . . args )
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return static_cast < Callback * > ( func ) - > call ( args . . . ) ;
2016-05-13 19:54:46 +00:00
}
private :
2019-07-02 14:27:15 +00:00
using call_type = R ( const CallbackBase * , ArgTs . . . ) ;
2016-09-27 18:27:17 +00:00
2019-07-02 14:27:15 +00:00
// *INDENT-OFF*
2016-09-27 18:27:17 +00:00
// Generate operations for function object
2019-07-02 14:27:15 +00:00
// Storage assumed to be uninitialised - destructor should have already been called if it was previously used
// When generating, function object should always be moved
template < typename F , typename = std : : enable_if_t < ! std : : is_lvalue_reference < F > : : value > >
void generate ( F & & f )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
# ifndef __ICCARM__ /* This assert fails on IAR for unknown reason */
static_assert ( std : : is_same < decltype ( target_call < F > ) , call_type > : : value , " Call type mismatch " ) ;
# endif
static_assert ( sizeof ( Callback ) = = sizeof ( CallbackBase ) , " Callback should be same size as CallbackBase " ) ;
static_assert ( std : : is_trivially_copyable < CallbackBase > : : value , " CallbackBase expected to be TriviallyCopyable " ) ;
// Set the control pointer
# if MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
// Generates one static ops for each <F,R,ArgTs...> tuple
// But the functions used for copy/move/dtor depend only on F, and even then only if non-trivial.
// `call` is type-erased - we cast from our call_type to the void (*)(void) in CallbackBase
// This should be a ROMmed constant table, but formally it can't be constexpr because of the reinterpret_cast :(
2016-09-27 18:27:17 +00:00
static const ops ops = {
2019-07-02 14:27:15 +00:00
reinterpret_cast < void ( * ) ( ) > ( target_call < F > ) ,
std : : is_trivially_copy_constructible < F > : : value ? trivial_target_copy : target_copy < F > ,
std : : is_trivially_destructible < F > : : value ? trivial_target_dtor : target_dtor < F > ,
2016-09-27 18:27:17 +00:00
} ;
_ops = & ops ;
2019-07-02 14:27:15 +00:00
# else // MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
// Avoid the need for the const ops table - just one function pointer in the Callback itself
_call = reinterpret_cast < void ( * ) ( ) > ( target_call < F > ) ;
static_assert ( std : : is_trivially_copyable < F > : : value , " F must be TriviallyCopyable. Turn on Mbed configuration option 'platform.callback-nontrivial' to use more complex function objects " ) ;
static_assert ( std : : is_trivially_copyable < Callback > : : value , " Callback expected to be TriviallyCopyable " ) ;
# endif // MBED_CONF_PLATFORM_CALLBACK_NONTRIVIAL
// Move the functor into storage
static_assert ( sizeof ( F ) < = sizeof ( Store ) & & alignof ( F ) < = alignof ( Store ) ,
" Type F must not exceed the size of the Callback class " ) ;
new ( & _storage ) F ( std : : move ( f ) ) ;
# if MBED_CONF_PLATFORM_CALLBACK_COMPARABLE
// Zero out any padding - required for Callback-to-Callback comparisons.
if ( sizeof ( F ) < sizeof ( Store ) ) {
std : : memset ( reinterpret_cast < char * > ( & _storage ) + sizeof ( F ) , 0 , sizeof ( Store ) - sizeof ( F ) ) ;
}
# endif
2016-09-27 18:27:17 +00:00
}
2019-07-02 14:27:15 +00:00
// *INDENT-ON*
2016-09-27 18:27:17 +00:00
2019-07-02 14:27:15 +00:00
// Target call routine - custom needed for each <F,R,ArgTs...> tuple
2016-10-03 23:33:25 +00:00
template < typename F >
2019-07-02 14:27:15 +00:00
static R target_call ( const CallbackBase * p , ArgTs . . . args )
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
// Need for const_cast here correlates to a std::function bug - see P0045 and N4159
F & f = const_cast < F & > ( reinterpret_cast < const F & > ( p - > _storage ) ) ;
return detail : : invoke_r < R > ( f , std : : forward < ArgTs > ( args ) . . . ) ;
2016-10-03 23:33:25 +00:00
}
2016-05-13 19:54:46 +00:00
} ;
2019-06-24 10:06:37 +00:00
// Internally used event type
2019-07-02 14:27:15 +00:00
using event_callback_t = Callback < void ( int ) > ;
Added support for cv-qualifiers in Callback class
Additionally, the following changes were don to avoid combinatorial
explosion in function overloads as a result of adding cv-qualifiers:
- Added convenience function for inferred type
- Deprecated callback overloads qhere cv-qualifiers are not scalable
Supported overloads:
callback(void (*f)(A...));
callback(const Callback<R(A...)> &);
callback(T *t, void (*f)(T*, A...));
callback(const T *t, void (*f)(const T*, A...));
callback(volatile T *t, void (*f)(volatile T*, A...));
callback(const volatile T *t, void (*f)(const volatile T*, A...));
callback(T *t, void (T::*f)(A...));
callback(const T *t, void (T::*f)(A...) const);
callback(volatile T *t, void (T::*f)(A...) volatile);
callback(const volatile T *t, void (T::*f)(A...) const volatile);
2016-08-18 18:28:57 +00:00
2019-07-02 14:27:15 +00:00
template < typename R , typename . . . ArgTs >
void swap ( Callback < R ( ArgTs . . . ) > & lhs , Callback < R ( ArgTs . . . ) > & rhs ) noexcept
{
lhs . swap ( rhs ) ;
}
2016-09-23 08:29:14 +00:00
2018-10-17 21:49:38 +00:00
/** Create a callback class with type inferred from the arguments
2016-08-19 20:49:49 +00:00
*
2016-09-23 08:29:14 +00:00
* @ param func Static function to attach
2018-10-17 21:49:38 +00:00
* @ return Callback with inferred type
2016-08-19 20:49:49 +00:00
*/
2019-06-24 10:06:37 +00:00
template < typename R , typename . . . ArgTs >
2019-07-02 14:27:15 +00:00
Callback < R ( ArgTs . . . ) > callback ( R ( * func ) ( ArgTs . . . ) = nullptr ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return Callback < R ( ArgTs . . . ) > ( func ) ;
Added support for cv-qualifiers in Callback class
Additionally, the following changes were don to avoid combinatorial
explosion in function overloads as a result of adding cv-qualifiers:
- Added convenience function for inferred type
- Deprecated callback overloads qhere cv-qualifiers are not scalable
Supported overloads:
callback(void (*f)(A...));
callback(const Callback<R(A...)> &);
callback(T *t, void (*f)(T*, A...));
callback(const T *t, void (*f)(const T*, A...));
callback(volatile T *t, void (*f)(volatile T*, A...));
callback(const volatile T *t, void (*f)(const volatile T*, A...));
callback(T *t, void (T::*f)(A...));
callback(const T *t, void (T::*f)(A...) const);
callback(volatile T *t, void (T::*f)(A...) volatile);
callback(const volatile T *t, void (T::*f)(A...) const volatile);
2016-08-18 18:28:57 +00:00
}
2018-10-17 21:49:38 +00:00
/** Create a callback class with type inferred from the arguments
2016-08-19 20:49:49 +00:00
*
2016-09-23 08:29:14 +00:00
* @ param func Static function to attach
2018-10-17 21:49:38 +00:00
* @ return Callback with inferred type
2016-08-19 20:49:49 +00:00
*/
2019-06-24 10:06:37 +00:00
template < typename R , typename . . . ArgTs >
Callback < R ( ArgTs . . . ) > callback ( const Callback < R ( ArgTs . . . ) > & func )
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return Callback < R ( ArgTs . . . ) > ( func ) ;
Added support for cv-qualifiers in Callback class
Additionally, the following changes were don to avoid combinatorial
explosion in function overloads as a result of adding cv-qualifiers:
- Added convenience function for inferred type
- Deprecated callback overloads qhere cv-qualifiers are not scalable
Supported overloads:
callback(void (*f)(A...));
callback(const Callback<R(A...)> &);
callback(T *t, void (*f)(T*, A...));
callback(const T *t, void (*f)(const T*, A...));
callback(volatile T *t, void (*f)(volatile T*, A...));
callback(const volatile T *t, void (*f)(const volatile T*, A...));
callback(T *t, void (T::*f)(A...));
callback(const T *t, void (T::*f)(A...) const);
callback(volatile T *t, void (T::*f)(A...) volatile);
callback(const volatile T *t, void (T::*f)(A...) const volatile);
2016-08-18 18:28:57 +00:00
}
2018-10-17 21:49:38 +00:00
/** Create a callback class with type inferred from the arguments
2016-08-19 20:49:49 +00:00
*
2019-07-02 14:27:15 +00:00
* @ param func Static function to attach
2018-10-17 21:49:38 +00:00
* @ return Callback with inferred type
2016-08-19 20:49:49 +00:00
*/
2019-07-02 14:27:15 +00:00
template < typename R , typename . . . ArgTs >
Callback < R ( ArgTs . . . ) > callback ( Callback < R ( ArgTs . . . ) > & & func ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-07-02 14:27:15 +00:00
return Callback < R ( ArgTs . . . ) > ( std : : move ( func ) ) ;
Added support for cv-qualifiers in Callback class
Additionally, the following changes were don to avoid combinatorial
explosion in function overloads as a result of adding cv-qualifiers:
- Added convenience function for inferred type
- Deprecated callback overloads qhere cv-qualifiers are not scalable
Supported overloads:
callback(void (*f)(A...));
callback(const Callback<R(A...)> &);
callback(T *t, void (*f)(T*, A...));
callback(const T *t, void (*f)(const T*, A...));
callback(volatile T *t, void (*f)(volatile T*, A...));
callback(const volatile T *t, void (*f)(const volatile T*, A...));
callback(T *t, void (T::*f)(A...));
callback(const T *t, void (T::*f)(A...) const);
callback(volatile T *t, void (T::*f)(A...) volatile);
callback(const volatile T *t, void (T::*f)(A...) const volatile);
2016-08-18 18:28:57 +00:00
}
2018-10-17 21:49:38 +00:00
/** Create a callback class with type inferred from the arguments
2016-08-19 20:49:49 +00:00
*
2016-09-23 08:29:14 +00:00
* @ param obj Optional pointer to object to bind to function
* @ param method Member function to attach
2018-10-17 21:49:38 +00:00
* @ return Callback with inferred type
2016-08-19 20:49:49 +00:00
*/
2019-06-24 10:06:37 +00:00
template < typename T , typename U , typename R , typename . . . ArgTs >
2019-07-02 14:27:15 +00:00
Callback < R ( ArgTs . . . ) > callback ( U * obj , R ( T : : * method ) ( ArgTs . . . ) ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return Callback < R ( ArgTs . . . ) > ( obj , method ) ;
Added support for cv-qualifiers in Callback class
Additionally, the following changes were don to avoid combinatorial
explosion in function overloads as a result of adding cv-qualifiers:
- Added convenience function for inferred type
- Deprecated callback overloads qhere cv-qualifiers are not scalable
Supported overloads:
callback(void (*f)(A...));
callback(const Callback<R(A...)> &);
callback(T *t, void (*f)(T*, A...));
callback(const T *t, void (*f)(const T*, A...));
callback(volatile T *t, void (*f)(volatile T*, A...));
callback(const volatile T *t, void (*f)(const volatile T*, A...));
callback(T *t, void (T::*f)(A...));
callback(const T *t, void (T::*f)(A...) const);
callback(volatile T *t, void (T::*f)(A...) volatile);
callback(const volatile T *t, void (T::*f)(A...) const volatile);
2016-08-18 18:28:57 +00:00
}
2019-06-24 10:06:37 +00:00
template < typename T , typename U , typename R , typename . . . ArgTs >
2019-07-02 14:27:15 +00:00
Callback < R ( ArgTs . . . ) > callback ( U * obj , R ( T : : * method ) ( ArgTs . . . ) & ) noexcept
{
return Callback < R ( ArgTs . . . ) > ( obj , method ) ;
}
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback < R ( ArgTs . . . ) > callback ( const U * obj , R ( T : : * method ) ( ArgTs . . . ) const ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return Callback < R ( ArgTs . . . ) > ( obj , method ) ;
2016-09-23 08:29:14 +00:00
}
2016-08-19 20:49:49 +00:00
2019-06-24 10:06:37 +00:00
template < typename T , typename U , typename R , typename . . . ArgTs >
2019-07-02 14:27:15 +00:00
Callback < R ( ArgTs . . . ) > callback ( const U * obj , R ( T : : * method ) ( ArgTs . . . ) const & ) noexcept
{
return Callback < R ( ArgTs . . . ) > ( obj , method ) ;
}
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback < R ( ArgTs . . . ) > callback ( volatile U * obj , R ( T : : * method ) ( ArgTs . . . ) volatile ) noexcept
{
return Callback < R ( ArgTs . . . ) > ( obj , method ) ;
}
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback < R ( ArgTs . . . ) > callback ( volatile U * obj , R ( T : : * method ) ( ArgTs . . . ) volatile & ) noexcept
{
return Callback < R ( ArgTs . . . ) > ( obj , method ) ;
}
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback < R ( ArgTs . . . ) > callback ( const volatile U * obj , R ( T : : * method ) ( ArgTs . . . ) const volatile ) noexcept
{
return Callback < R ( ArgTs . . . ) > ( obj , method ) ;
}
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback < R ( ArgTs . . . ) > callback ( const volatile U * obj , R ( T : : * method ) ( ArgTs . . . ) const volatile & ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return Callback < R ( ArgTs . . . ) > ( obj , method ) ;
Added support for cv-qualifiers in Callback class
Additionally, the following changes were don to avoid combinatorial
explosion in function overloads as a result of adding cv-qualifiers:
- Added convenience function for inferred type
- Deprecated callback overloads qhere cv-qualifiers are not scalable
Supported overloads:
callback(void (*f)(A...));
callback(const Callback<R(A...)> &);
callback(T *t, void (*f)(T*, A...));
callback(const T *t, void (*f)(const T*, A...));
callback(volatile T *t, void (*f)(volatile T*, A...));
callback(const volatile T *t, void (*f)(const volatile T*, A...));
callback(T *t, void (T::*f)(A...));
callback(const T *t, void (T::*f)(A...) const);
callback(volatile T *t, void (T::*f)(A...) volatile);
callback(const volatile T *t, void (T::*f)(A...) const volatile);
2016-08-18 18:28:57 +00:00
}
2018-10-17 21:49:38 +00:00
/** Create a callback class with type inferred from the arguments
2016-08-19 20:49:49 +00:00
*
2016-09-23 08:29:14 +00:00
* @ param func Static function to attach
* @ param arg Pointer argument to function
2018-10-17 21:49:38 +00:00
* @ return Callback with inferred type
2016-08-19 20:49:49 +00:00
*/
2019-06-24 10:06:37 +00:00
template < typename T , typename U , typename R , typename . . . ArgTs >
2019-07-02 14:27:15 +00:00
Callback < R ( ArgTs . . . ) > callback ( R ( * func ) ( T * , ArgTs . . . ) , U * arg ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return Callback < R ( ArgTs . . . ) > ( func , arg ) ;
2016-09-23 08:29:14 +00:00
}
2019-06-24 10:06:37 +00:00
template < typename T , typename U , typename R , typename . . . ArgTs >
2019-07-02 14:27:15 +00:00
Callback < R ( ArgTs . . . ) > callback ( R ( * func ) ( const T * , ArgTs . . . ) , const U * arg ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return Callback < R ( ArgTs . . . ) > ( func , arg ) ;
2016-09-23 08:29:14 +00:00
}
2019-06-24 10:06:37 +00:00
template < typename T , typename U , typename R , typename . . . ArgTs >
2019-07-02 14:27:15 +00:00
Callback < R ( ArgTs . . . ) > callback ( R ( * func ) ( volatile T * , ArgTs . . . ) , volatile U * arg ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return Callback < R ( ArgTs . . . ) > ( func , arg ) ;
2016-09-23 08:29:14 +00:00
}
2019-06-24 10:06:37 +00:00
template < typename T , typename U , typename R , typename . . . ArgTs >
2019-07-02 14:27:15 +00:00
Callback < R ( ArgTs . . . ) > callback ( R ( * func ) ( const volatile T * , ArgTs . . . ) , const volatile U * arg ) noexcept
2018-06-27 14:09:15 +00:00
{
2019-06-24 10:06:37 +00:00
return Callback < R ( ArgTs . . . ) > ( func , arg ) ;
2016-08-25 17:25:01 +00:00
}
2019-07-02 14:27:15 +00:00
/** Create a Create a callback class with type inferred from the arguments
* @ param f Function object to attach
* @ note The function object is limited to a single word of storage
*/
template < typename F >
Callback < detail : : unqualify_fn_t < detail : : member_type_t < decltype ( & mstd : : remove_cvref_t < F > : : operator ( ) ) > > >
callback ( F & & f )
{
return Callback < detail : : unqualify_fn_t < detail : : member_type_t < decltype ( & mstd : : remove_cvref_t < F > : : operator ( ) ) > > > ( std : : forward < F > ( f ) ) ;
}
# if __cplusplus >= 201703 || __cpp_deduction_guides >= 201703
/* Deduction guides that can replace callback() helper */
template < typename R , typename . . . Args >
Callback ( R ( * ) ( Args . . . ) ) - > Callback < R ( Args . . . ) > ;
template < typename F >
Callback ( F ) - > Callback < detail : : unqualify_fn_t < detail : : member_type_t < decltype ( & F : : operator ( ) ) > > > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( U * obj , R ( T : : * method ) ( ArgTs . . . ) ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( U * obj , R ( T : : * method ) ( ArgTs . . . ) & ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( const U * obj , R ( T : : * method ) ( ArgTs . . . ) const ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( const U * obj , R ( T : : * method ) ( ArgTs . . . ) const & ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( volatile U * obj , R ( T : : * method ) ( ArgTs . . . ) volatile ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( volatile U * obj , R ( T : : * method ) ( ArgTs . . . ) volatile & ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( const volatile U * obj , R ( T : : * method ) ( ArgTs . . . ) const volatile ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( const volatile U * obj , R ( T : : * method ) ( ArgTs . . . ) const volatile & ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( R ( * func ) ( T * , ArgTs . . . ) , U * arg ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( R ( * func ) ( const T * , ArgTs . . . ) , const U * arg ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( R ( * func ) ( volatile T * , ArgTs . . . ) , volatile U * arg ) - > Callback < R ( ArgTs . . . ) > ;
template < typename T , typename U , typename R , typename . . . ArgTs >
Callback ( R ( * func ) ( const volatile T * , ArgTs . . . ) , const volatile U * arg ) - > Callback < R ( ArgTs . . . ) > ;
# endif
2017-10-24 15:05:45 +00:00
/**@}*/
/**@}*/
2016-05-13 19:54:46 +00:00
} // namespace mbed
2016-09-26 13:09:18 +00:00
# endif