diff options
author | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2017-05-22 10:10:05 +0900 |
---|---|---|
committer | Kitsune Ral <Kitsune-Ral@users.sf.net> | 2017-05-22 10:10:05 +0900 |
commit | f51d9ba6c4aa7d682eac7aae49a025721d298045 (patch) | |
tree | b43477c2a5a75eec8a57e039cadbdcdc604f8e76 | |
parent | bb26ca86ad350f2562b51284e7c631b1e4f77106 (diff) | |
download | libquotient-f51d9ba6c4aa7d682eac7aae49a025721d298045.tar.gz libquotient-f51d9ba6c4aa7d682eac7aae49a025721d298045.zip |
Dispatch<>: Allow nullptr for a function; special-case GCC 4.8
-rw-r--r-- | util.h | 50 |
1 files changed, 33 insertions, 17 deletions
@@ -150,12 +150,18 @@ namespace QMatrixClient * \tparam ResultT - the desired type of a picked function invocation (mandatory) * \tparam ArgTs - function argument types (deduced) */ +#if __GNUC__ < 5 && __GNUC_MINOR__ < 9 + // GCC 4.8 cannot cope with parameter packs inside lambdas; so provide a single + // argument version of Dispatch<> that we only need so far. + template <typename ResultT, typename ArgT> +#else template <typename ResultT, typename... ArgTs> +#endif class Dispatch { - // We take a chapter from functional programming here: Dispatch<> - // uses a function that in turn accepts a function as its argument. - // The sole purpose of the outer function (initialized by + // The implementation takes a chapter from functional programming: + // Dispatch<> uses a function that in turn accepts a function as its + // argument. The sole purpose of the outer function (initialized by // a lambda-expression in the constructor) is to store the arguments // to any of the functions later looked up. The inner function (its // type is defined by fn_t alias) is the one returned by lookup() @@ -164,21 +170,25 @@ namespace QMatrixClient // It's a bit counterintuitive to specify function parameters before // the list of functions but otherwise it would take several overloads // here to match all the ways a function-like behaviour can be done: - // reference-to-function, pointer-to-function, function object. For - // each of these overloads, we'd have to carefully retrieve the list - // of parameters and cover up possible reference-vs-value - // incompatibilities. Instead, you show what you have and if it's - // possible to bring all your functions to the same std::function<> - // based on what you have as parameters, the code will compile. If - // it's not possible, modern compilers are already good enough at - // pinpointing a specific place where types don't match. - using fn_t = std::function<ResultT(ArgTs...)>; + // reference-to-function, pointer-to-function, function object. This + // probably could be done as well but I preferred a more compact + // solution: you show what you have and if it's possible to bring all + // your functions to the same std::function<> based on what you have + // as parameters, the code will compile. If it's not possible, modern + // compilers are already good enough at pinpointing a specific place + // where types don't match. public: +#if __GNUC__ < 5 && __GNUC_MINOR__ < 9 + using fn_t = std::function<ResultT(ArgT)>; + explicit Dispatch(ArgT&& arg) + : boundArgs([=](fn_t &&f) { return f(std::move(arg)); }) + { } +#else + using fn_t = std::function<ResultT(ArgTs...)>; explicit Dispatch(ArgTs&&... args) - : boundArgs([=](fn_t &&f) { - return f(std::forward<ArgTs...>(args)...); - }) + : boundArgs([=](fn_t &&f) { return f(std::move(args)...); }) { } +#endif template <typename... LookupParamTs> ResultT to(LookupParamTs&&... lookupParams) @@ -190,12 +200,18 @@ namespace QMatrixClient // generic (because std::function is covariant by return types and // contravariant by argument types (see the link in the Doxygen // part of the comments). + auto fn = lookup<fn_t>(std::forward<LookupParamTs>(lookupParams)...); // 2. Passing the result of lookup() to boundArgs() invokes the // lambda-expression mentioned in the constructor, which simply // invokes this passed function with a set of arguments captured // by lambda. - return boundArgs( - lookup<fn_t>(std::forward<LookupParamTs>(lookupParams)...)); + if (fn) + return boundArgs(std::move(fn)); + + // A shortcut to allow passing nullptr for a function; + // a default-constructed ResultT will be returned + // (for pointers, it will be nullptr) + return {}; } private: |