diff options
Diffstat (limited to 'src/FunctionRef.h')
-rw-r--r-- | src/FunctionRef.h | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/src/FunctionRef.h b/src/FunctionRef.h new file mode 100644 index 000000000..8215fd0db --- /dev/null +++ b/src/FunctionRef.h @@ -0,0 +1,58 @@ + +#pragma once + +// Declared only so it can be partially specialized +template <class Signature> +class cFunctionRef; + +/** A light-weight, type-erased reference to a function object. +This is similar to a std::function but doesn't copy the function object +which means that mutable function objects will be modified for the caller +but would not be if using a std::function (See #3990 for implications of this). +A cFunctionRef has no empty state but is non-owning and so is safe to call +as long as the referred object is still alive. */ +template <class Ret, class... Args> +class cFunctionRef<Ret(Args...)> +{ +public: + /** Construct from a function object. */ + template <class FunctionObject> + cFunctionRef(FunctionObject && a_FunctionObject) + { + // Store an opaque reference to the object. + m_CallableData = &a_FunctionObject; + + // Along with a function that knows how to call the object. + m_CallFunction = &ObjectFunctionCaller<FunctionObject>; + } + + /** Call the referenced function object */ + Ret operator () (Args... a_Args) + { + return m_CallFunction(m_CallableData, std::forward<Args>(a_Args)...); + } + +private: + + /** Function that performs the call. */ + template <class ObjectType> + static Ret ObjectFunctionCaller(void * a_Callable, Args... a_Args) + { + // Convert opaque reference to the concrete type. + using ObjectPtr = typename std::add_pointer<ObjectType>::type; + auto & Object = *static_cast<ObjectPtr>(a_Callable); + + // Forward the call down to the object. + return Object(std::forward<Args>(a_Args)...); + } + + using cCallFunction = Ret(*)(void *, Args...); + + /** Type erased reference to a callable. */ + void * m_CallableData; + + /** Function that knows how to call the type erased reference. */ + cCallFunction m_CallFunction; +}; + + |