/* Delegate.h - An efficient interchangeable C function ptr and C++ std::function delegate Copyright (c) 2019 Dirk O. Kaar. All rights reserved. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __Delegate_h #define __Delegate_h #if defined(ESP8266) #include #elif defined(ESP32) #include #else #define ICACHE_RAM_ATTR #define IRAM_ATTR #endif #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) #include #include #else #include "circular_queue/ghostl.h" #endif namespace detail { template static R IRAM_ATTR vPtrToFunPtrExec(void* fn, P... args) { using target_type = R(P...); return reinterpret_cast(fn)(std::forward(args...)); } #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) template class DelegatePImpl { public: using target_type = R(P...); protected: using FunPtr = target_type*; using FunAPtr = R(*)(A, P...); using FunVPPtr = R(*)(void*, P...); using FunctionType = std::function; public: DelegatePImpl() { kind = FP; fn = nullptr; } DelegatePImpl(std::nullptr_t) { kind = FP; fn = nullptr; } ~DelegatePImpl() { if (FUNC == kind) functional.~FunctionType(); else if (FPA == kind) obj.~A(); } DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; if (FUNC == del.kind) { new (&functional) FunctionType(del.functional); } else if (FPA == del.kind) { fnA = del.fnA; new (&obj) A(del.obj); } else { fn = del.fn; } } DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; if (FUNC == del.kind) { new (&functional) FunctionType(std::move(del.functional)); } else if (FPA == del.kind) { fnA = del.fnA; new (&obj) A(std::move(del.obj)); } else { fn = del.fn; } } DelegatePImpl(FunAPtr fnA, const A& obj) { kind = FPA; DelegatePImpl::fnA = fnA; new (&this->obj) A(obj); } DelegatePImpl(FunAPtr fnA, A&& obj) { kind = FPA; DelegatePImpl::fnA = fnA; new (&this->obj) A(std::move(obj)); } DelegatePImpl(FunPtr fn) { kind = FP; DelegatePImpl::fn = fn; } template DelegatePImpl(F functional) { kind = FUNC; new (&this->functional) FunctionType(std::forward(functional)); } DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; if (kind != del.kind) { if (FUNC == kind) { functional.~FunctionType(); } else if (FPA == kind) { obj.~A(); } if (FUNC == del.kind) { new (&this->functional) FunctionType(); } else if (FPA == del.kind) { new (&obj) A; } kind = del.kind; } if (FUNC == del.kind) { functional = del.functional; } else if (FPA == del.kind) { fnA = del.fnA; obj = del.obj; } else { fn = del.fn; } return *this; } DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; if (kind != del.kind) { if (FUNC == kind) { functional.~FunctionType(); } else if (FPA == kind) { obj.~A(); } if (FUNC == del.kind) { new (&this->functional) FunctionType(); } else if (FPA == del.kind) { new (&obj) A; } kind = del.kind; } if (FUNC == del.kind) { functional = std::move(del.functional); } else if (FPA == del.kind) { fnA = del.fnA; obj = std::move(del.obj); } else { fn = del.fn; } return *this; } DelegatePImpl& operator=(FunPtr fn) { if (FUNC == kind) { functional.~FunctionType(); } else if (FPA == kind) { obj.~A(); } kind = FP; this->fn = fn; return *this; } DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) { functional.~FunctionType(); } else if (FPA == kind) { obj.~A(); } kind = FP; fn = nullptr; return *this; } operator bool() const { if (FP == kind) { return fn; } else if (FPA == kind) { return fnA; } else { return functional ? true : false; } } static R IRAM_ATTR vPtrToFunAPtrExec(void* self, P... args) { return static_cast(self)->fnA( static_cast(self)->obj, std::forward(args...)); }; operator FunVPPtr() const { if (FP == kind) { return vPtrToFunPtrExec; } else if (FPA == kind) { return vPtrToFunAPtrExec; } else { return [](void* self, P... args) -> R { return static_cast(self)->functional(std::forward(args...)); }; } } void* arg() const { if (FP == kind) { return reinterpret_cast(fn); } else { return const_cast(this); } } operator FunctionType() const { if (FP == kind) { return fn; } else if (FPA == kind) { return [this](P... args) { return fnA(obj, std::forward(args...)); }; } else { return functional; } } R IRAM_ATTR operator()(P... args) const { if (FP == kind) { return fn(std::forward(args...)); } else if (FPA == kind) { return fnA(obj, std::forward(args...)); } else { return functional(std::forward(args...)); } } protected: enum { FUNC, FP, FPA } kind; union { FunctionType functional; FunPtr fn; struct { FunAPtr fnA; A obj; }; }; }; #else template class DelegatePImpl { public: using target_type = R(P...); protected: using FunPtr = target_type*; using FunAPtr = R(*)(A, P...); using FunVPPtr = R(*)(void*, P...); public: DelegatePImpl() { kind = FP; fn = nullptr; } DelegatePImpl(std::nullptr_t) { kind = FP; fn = nullptr; } DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; if (FPA == del.kind) { fnA = del.fnA; obj = del.obj; } else { fn = del.fn; } } DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; if (FPA == del.kind) { fnA = del.fnA; obj = std::move(del.obj); } else { fn = del.fn; } } DelegatePImpl(FunAPtr fnA, const A& obj) { kind = FPA; DelegatePImpl::fnA = fnA; this->obj = obj; } DelegatePImpl(FunAPtr fnA, A&& obj) { kind = FPA; DelegatePImpl::fnA = fnA; this->obj = std::move(obj); } DelegatePImpl(FunPtr fn) { kind = FP; DelegatePImpl::fn = fn; } template DelegatePImpl(F fn) { kind = FP; DelegatePImpl::fn = std::forward(fn); } DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; if (kind != del.kind) { if (FPA == kind) { obj = {}; } kind = del.kind; } if (FPA == del.kind) { fnA = del.fnA; obj = del.obj; } else { fn = del.fn; } return *this; } DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; if (kind != del.kind) { if (FPA == kind) { obj = {}; } kind = del.kind; } if (FPA == del.kind) { fnA = del.fnA; obj = std::move(del.obj); } else { fn = del.fn; } return *this; } DelegatePImpl& operator=(FunPtr fn) { if (FPA == kind) { obj = {}; } kind = FP; this->fn = fn; return *this; } DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) { obj = {}; } kind = FP; fn = nullptr; return *this; } operator bool() const { if (FP == kind) { return fn; } else { return fnA; } } static R IRAM_ATTR vPtrToFunAPtrExec(void* self, P... args) { return static_cast(self)->fnA( static_cast(self)->obj, std::forward(args...)); }; operator FunVPPtr() const { if (FP == kind) { return vPtrToFunPtrExec; } else { return vPtrToFunAPtrExec; } } void* arg() const { if (FP == kind) { return reinterpret_cast(fn); } else { return const_cast(this); } } R IRAM_ATTR operator()(P... args) const { if (FP == kind) { return fn(std::forward(args...)); } else { return fnA(obj, std::forward(args...)); } } protected: enum { FP, FPA } kind; union { FunPtr fn; FunAPtr fnA; }; A obj; }; #endif #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) template class DelegatePImpl { public: using target_type = R(P...); protected: using FunPtr = target_type*; using FunctionType = std::function; using FunVPPtr = R(*)(void*, P...); public: DelegatePImpl() { kind = FP; fn = nullptr; } DelegatePImpl(std::nullptr_t) { kind = FP; fn = nullptr; } ~DelegatePImpl() { if (FUNC == kind) functional.~FunctionType(); } DelegatePImpl(const DelegatePImpl& del) { kind = del.kind; if (FUNC == del.kind) { new (&functional) FunctionType(del.functional); } else { fn = del.fn; } } DelegatePImpl(DelegatePImpl&& del) { kind = del.kind; if (FUNC == del.kind) { new (&functional) FunctionType(std::move(del.functional)); } else { fn = del.fn; } } DelegatePImpl(FunPtr fn) { kind = FP; DelegatePImpl::fn = fn; } template DelegatePImpl(F functional) { kind = FUNC; new (&this->functional) FunctionType(std::forward(functional)); } DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); } else if (FUNC != kind && FUNC == del.kind) { new (&this->functional) FunctionType(); } kind = del.kind; if (FUNC == del.kind) { functional = del.functional; } else { fn = del.fn; } return *this; } DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); } else if (FUNC != kind && FUNC == del.kind) { new (&this->functional) FunctionType(); } kind = del.kind; if (FUNC == del.kind) { functional = std::move(del.functional); } else { fn = del.fn; } return *this; } DelegatePImpl& operator=(FunPtr fn) { if (FUNC == kind) { functional.~FunctionType(); kind = FP; } DelegatePImpl::fn = fn; return *this; } DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) { functional.~FunctionType(); } kind = FP; fn = nullptr; return *this; } operator bool() const { if (FP == kind) { return fn; } else { return functional ? true : false; } } operator FunVPPtr() const { if (FP == kind) { return vPtrToFunPtrExec; } else { return [](void* self, P... args) -> R { return static_cast(self)->functional(std::forward(args...)); }; } } void* arg() const { if (FP == kind) { return reinterpret_cast(fn); } else { return const_cast(this); } } operator FunctionType() const { if (FP == kind) { return fn; } else { return functional; } } R IRAM_ATTR operator()(P... args) const { if (FP == kind) { return fn(std::forward(args...)); } else { return functional(std::forward(args...)); } } protected: enum { FUNC, FP } kind; union { FunctionType functional; FunPtr fn; }; }; #else template class DelegatePImpl { public: using target_type = R(P...); protected: using FunPtr = target_type*; using FunVPPtr = R(*)(void*, P...); public: DelegatePImpl() { fn = nullptr; } DelegatePImpl(std::nullptr_t) { fn = nullptr; } DelegatePImpl(const DelegatePImpl& del) { fn = del.fn; } DelegatePImpl(DelegatePImpl&& del) { fn = std::move(del.fn); } DelegatePImpl(FunPtr fn) { DelegatePImpl::fn = fn; } template DelegatePImpl(F fn) { DelegatePImpl::fn = std::forward(fn); } DelegatePImpl& operator=(const DelegatePImpl& del) { if (this == &del) return *this; fn = del.fn; return *this; } DelegatePImpl& operator=(DelegatePImpl&& del) { if (this == &del) return *this; fn = std::move(del.fn); return *this; } DelegatePImpl& operator=(FunPtr fn) { DelegatePImpl::fn = fn; return *this; } DelegatePImpl& IRAM_ATTR operator=(std::nullptr_t) { fn = nullptr; return *this; } operator bool() const { return fn; } operator FunVPPtr() const { return vPtrToFunPtrExec; } void* arg() const { return reinterpret_cast(fn); } R IRAM_ATTR operator()(P... args) const { return fn(std::forward(args...)); } protected: FunPtr fn; }; #endif #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) template class DelegateImpl { public: using target_type = R(); protected: using FunPtr = target_type*; using FunAPtr = R(*)(A); using FunctionType = std::function; using FunVPPtr = R(*)(void*); public: DelegateImpl() { kind = FP; fn = nullptr; } DelegateImpl(std::nullptr_t) { kind = FP; fn = nullptr; } ~DelegateImpl() { if (FUNC == kind) functional.~FunctionType(); else if (FPA == kind) obj.~A(); } DelegateImpl(const DelegateImpl& del) { kind = del.kind; if (FUNC == del.kind) { new (&functional) FunctionType(del.functional); } else if (FPA == del.kind) { fnA = del.fnA; new (&obj) A(del.obj); } else { fn = del.fn; } } DelegateImpl(DelegateImpl&& del) { kind = del.kind; if (FUNC == del.kind) { new (&functional) FunctionType(std::move(del.functional)); } else if (FPA == del.kind) { fnA = del.fnA; new (&obj) A(std::move(del.obj)); } else { fn = del.fn; } } DelegateImpl(FunAPtr fnA, const A& obj) { kind = FPA; DelegateImpl::fnA = fnA; new (&this->obj) A(obj); } DelegateImpl(FunAPtr fnA, A&& obj) { kind = FPA; DelegateImpl::fnA = fnA; new (&this->obj) A(std::move(obj)); } DelegateImpl(FunPtr fn) { kind = FP; DelegateImpl::fn = fn; } template DelegateImpl(F functional) { kind = FUNC; new (&this->functional) FunctionType(std::forward(functional)); } DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; if (kind != del.kind) { if (FUNC == kind) { functional.~FunctionType(); } else if (FPA == kind) { obj.~A(); } if (FUNC == del.kind) { new (&this->functional) FunctionType(); } else if (FPA == del.kind) { new (&obj) A; } kind = del.kind; } if (FUNC == del.kind) { functional = del.functional; } else if (FPA == del.kind) { fnA = del.fnA; obj = del.obj; } else { fn = del.fn; } return *this; } DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; if (kind != del.kind) { if (FUNC == kind) { functional.~FunctionType(); } else if (FPA == kind) { obj.~A(); } if (FUNC == del.kind) { new (&this->functional) FunctionType(); } else if (FPA == del.kind) { new (&obj) A; } kind = del.kind; } if (FUNC == del.kind) { functional = std::move(del.functional); } else if (FPA == del.kind) { fnA = del.fnA; obj = std::move(del.obj); } else { fn = del.fn; } return *this; } DelegateImpl& operator=(FunPtr fn) { if (FUNC == kind) { functional.~FunctionType(); } else if (FPA == kind) { obj.~A(); } kind = FP; this->fn = fn; return *this; } DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) { functional.~FunctionType(); } else if (FPA == kind) { obj.~A(); } kind = FP; fn = nullptr; return *this; } operator bool() const { if (FP == kind) { return fn; } else if (FPA == kind) { return fnA; } else { return functional ? true : false; } } static R IRAM_ATTR vPtrToFunAPtrExec(void* self) { return static_cast(self)->fnA( static_cast(self)->obj); }; operator FunVPPtr() const { if (FP == kind) { return reinterpret_cast(fn); } else if (FPA == kind) { return vPtrToFunAPtrExec; } else { return [](void* self) -> R { return static_cast(self)->functional(); }; } } void* arg() const { if (FP == kind) { return nullptr; } else { return const_cast(this); } } operator FunctionType() const { if (FP == kind) { return fn; } else if (FPA == kind) { return [this]() { return fnA(obj); }; } else { return functional; } } R IRAM_ATTR operator()() const { if (FP == kind) { return fn(); } else if (FPA == kind) { return fnA(obj); } else { return functional(); } } protected: enum { FUNC, FP, FPA } kind; union { FunctionType functional; FunPtr fn; struct { FunAPtr fnA; A obj; }; }; }; #else template class DelegateImpl { public: using target_type = R(); protected: using FunPtr = target_type*; using FunAPtr = R(*)(A); using FunVPPtr = R(*)(void*); public: DelegateImpl() { kind = FP; fn = nullptr; } DelegateImpl(std::nullptr_t) { kind = FP; fn = nullptr; } DelegateImpl(const DelegateImpl& del) { kind = del.kind; if (FPA == del.kind) { fnA = del.fnA; obj = del.obj; } else { fn = del.fn; } } DelegateImpl(DelegateImpl&& del) { kind = del.kind; if (FPA == del.kind) { fnA = del.fnA; obj = std::move(del.obj); } else { fn = del.fn; } } DelegateImpl(FunAPtr fnA, const A& obj) { kind = FPA; DelegateImpl::fnA = fnA; this->obj = obj; } DelegateImpl(FunAPtr fnA, A&& obj) { kind = FPA; DelegateImpl::fnA = fnA; this->obj = std::move(obj); } DelegateImpl(FunPtr fn) { kind = FP; DelegateImpl::fn = fn; } template DelegateImpl(F fn) { kind = FP; DelegateImpl::fn = std::forward(fn); } DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; if (kind != del.kind) { if (FPA == kind) { obj = {}; } kind = del.kind; } if (FPA == del.kind) { fnA = del.fnA; obj = del.obj; } else { fn = del.fn; } return *this; } DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; if (kind != del.kind) { if (FPA == kind) { obj = {}; } kind = del.kind; } if (FPA == del.kind) { fnA = del.fnA; obj = std::move(del.obj); } else { fn = del.fn; } return *this; } DelegateImpl& operator=(FunPtr fn) { if (FPA == kind) { obj = {}; } kind = FP; this->fn = fn; return *this; } DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FPA == kind) { obj = {}; } kind = FP; fn = nullptr; return *this; } operator bool() const { if (FP == kind) { return fn; } else { return fnA; } } static R IRAM_ATTR vPtrToFunAPtrExec(void* self) { return static_cast(self)->fnA( static_cast(self)->obj); }; operator FunVPPtr() const { if (FP == kind) { return reinterpret_cast(fn); } else { return vPtrToFunAPtrExec; } } void* arg() const { if (FP == kind) { return nullptr; } else { return const_cast(this); } } R IRAM_ATTR operator()() const { if (FP == kind) { return fn(); } else { return fnA(obj); } } protected: enum { FP, FPA } kind; union { FunPtr fn; FunAPtr fnA; }; A obj; }; #endif #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) template class DelegateImpl { public: using target_type = R(); protected: using FunPtr = target_type*; using FunctionType = std::function; using FunVPPtr = R(*)(void*); public: DelegateImpl() { kind = FP; fn = nullptr; } DelegateImpl(std::nullptr_t) { kind = FP; fn = nullptr; } ~DelegateImpl() { if (FUNC == kind) functional.~FunctionType(); } DelegateImpl(const DelegateImpl& del) { kind = del.kind; if (FUNC == del.kind) { new (&functional) FunctionType(del.functional); } else { fn = del.fn; } } DelegateImpl(DelegateImpl&& del) { kind = del.kind; if (FUNC == del.kind) { new (&functional) FunctionType(std::move(del.functional)); } else { fn = del.fn; } } DelegateImpl(FunPtr fn) { kind = FP; DelegateImpl::fn = fn; } template DelegateImpl(F functional) { kind = FUNC; new (&this->functional) FunctionType(std::forward(functional)); } DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); } else if (FUNC != kind && FUNC == del.kind) { new (&this->functional) FunctionType(); } kind = del.kind; if (FUNC == del.kind) { functional = del.functional; } else { fn = del.fn; } return *this; } DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; if (FUNC == kind && FUNC != del.kind) { functional.~FunctionType(); } else if (FUNC != kind && FUNC == del.kind) { new (&this->functional) FunctionType(); } kind = del.kind; if (FUNC == del.kind) { functional = std::move(del.functional); } else { fn = del.fn; } return *this; } DelegateImpl& operator=(FunPtr fn) { if (FUNC == kind) { functional.~FunctionType(); kind = FP; } DelegateImpl::fn = fn; return *this; } DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { if (FUNC == kind) { functional.~FunctionType(); } kind = FP; fn = nullptr; return *this; } operator bool() const { if (FP == kind) { return fn; } else { return functional ? true : false; } } operator FunVPPtr() const { if (FP == kind) { return reinterpret_cast(fn); } else { return [](void* self) -> R { return static_cast(self)->functional(); }; } } void* arg() const { if (FP == kind) { return nullptr; } else { return const_cast(this); } } operator FunctionType() const { if (FP == kind) { return fn; } else { return functional; } } R IRAM_ATTR operator()() const { if (FP == kind) { return fn(); } else { return functional(); } } protected: enum { FUNC, FP } kind; union { FunctionType functional; FunPtr fn; }; }; #else template class DelegateImpl { public: using target_type = R(); protected: using FunPtr = target_type*; using FunVPPtr = R(*)(void*); public: DelegateImpl() { fn = nullptr; } DelegateImpl(std::nullptr_t) { fn = nullptr; } DelegateImpl(const DelegateImpl& del) { fn = del.fn; } DelegateImpl(DelegateImpl&& del) { fn = std::move(del.fn); } DelegateImpl(FunPtr fn) { DelegateImpl::fn = fn; } template DelegateImpl(F fn) { DelegateImpl::fn = std::forward(fn); } DelegateImpl& operator=(const DelegateImpl& del) { if (this == &del) return *this; fn = del.fn; return *this; } DelegateImpl& operator=(DelegateImpl&& del) { if (this == &del) return *this; fn = std::move(del.fn); return *this; } DelegateImpl& operator=(FunPtr fn) { DelegateImpl::fn = fn; return *this; } DelegateImpl& IRAM_ATTR operator=(std::nullptr_t) { fn = nullptr; return *this; } operator bool() const { return fn; } operator FunVPPtr() const { return reinterpret_cast(fn); } void* arg() const { return nullptr; } R IRAM_ATTR operator()() const { return fn(); } protected: FunPtr fn; }; #endif template class Delegate : private detail::DelegatePImpl { private: using typename detail::DelegatePImpl::FunVPPtr; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) using typename detail::DelegatePImpl::FunctionType; #endif public: using detail::DelegatePImpl::target_type; using detail::DelegatePImpl::DelegatePImpl; using detail::DelegatePImpl::operator=; using detail::DelegatePImpl::operator bool; using detail::DelegatePImpl::operator FunVPPtr; using detail::DelegatePImpl::arg; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) using detail::DelegatePImpl::operator FunctionType; #endif using detail::DelegatePImpl::operator(); }; template class Delegate : private detail::DelegatePImpl { private: using typename detail::DelegatePImpl::FunVPPtr; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) using typename detail::DelegatePImpl::FunctionType; #endif public: using detail::DelegatePImpl::target_type; using detail::DelegatePImpl::DelegatePImpl; using detail::DelegatePImpl::operator=; using detail::DelegatePImpl::operator bool; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) using detail::DelegatePImpl::operator FunctionType; #endif using detail::DelegatePImpl::operator(); operator FunVPPtr() const { if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) { return reinterpret_cast(detail::DelegatePImpl::fnA); } else { return detail::DelegatePImpl::operator FunVPPtr(); } } void* arg() const { if (detail::DelegatePImpl::FPA == detail::DelegatePImpl::kind) { return detail::DelegatePImpl::obj; } else { return detail::DelegatePImpl::arg(); } } }; template class Delegate : private detail::DelegateImpl { private: using typename detail::DelegateImpl::FunVPPtr; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) using typename detail::DelegateImpl::FunctionType; #endif public: using detail::DelegateImpl::target_type; using detail::DelegateImpl::DelegateImpl; using detail::DelegateImpl::operator=; using detail::DelegateImpl::operator bool; using detail::DelegateImpl::operator FunVPPtr; using detail::DelegateImpl::arg; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) using detail::DelegateImpl::operator FunctionType; #endif using detail::DelegateImpl::operator(); }; template class Delegate : private detail::DelegateImpl { private: using typename detail::DelegateImpl::FunVPPtr; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) using typename detail::DelegateImpl::FunctionType; #endif public: using detail::DelegateImpl::target_type; using detail::DelegateImpl::DelegateImpl; using detail::DelegateImpl::operator=; using detail::DelegateImpl::operator bool; #if !defined(ARDUINO) || defined(ESP8266) || defined(ESP32) using detail::DelegateImpl::operator FunctionType; #endif using detail::DelegateImpl::operator(); operator FunVPPtr() const { if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) { return reinterpret_cast(detail::DelegateImpl::fnA); } else { return detail::DelegateImpl::operator FunVPPtr(); } } void* arg() const { if (detail::DelegateImpl::FPA == detail::DelegateImpl::kind) { return detail::DelegateImpl::obj; } else { return detail::DelegateImpl::arg(); } } }; } template class Delegate; template class Delegate : public detail::Delegate { public: using detail::Delegate::Delegate; }; template class Delegate : public detail::Delegate { public: using detail::Delegate::Delegate; }; #endif // __Delegate_h