diff --git a/src/libs/solutions/tasking/tasktree.h b/src/libs/solutions/tasking/tasktree.h index 95fe3203901..fcc5df34392 100644 --- a/src/libs/solutions/tasking/tasktree.h +++ b/src/libs/solutions/tasking/tasktree.h @@ -214,6 +214,17 @@ protected: static GroupItem withTimeout(const GroupItem &item, std::chrono::milliseconds timeout, const std::function &handler = {}); + // Checks if Function may be invoked with Args and if Function's return type is Result. + template > + static constexpr bool isInvocable() + { + // Note, that std::is_invocable_r_v doesn't check Result type properly. + if constexpr (std::is_invocable_r_v) + return std::is_same_v>; + return false; + } + private: Type m_type = Type::Group; QList m_children; @@ -254,40 +265,33 @@ public: } private: - template + template static GroupSetupHandler wrapGroupSetup(Handler &&handler) { - static constexpr bool isDynamic - = std::is_same_v>>; - constexpr bool isVoid - = std::is_same_v>>; - static_assert(isDynamic || isVoid, - "Group setup handler needs to take no arguments and has to return " - "void or SetupResult. The passed handler doesn't fulfill these requirements."); + // S, V stands for: [S]etupResult, [V]oid + static constexpr bool isS = isInvocable(); + static constexpr bool isV = isInvocable(); + static_assert(isS || isV, + "Group setup handler needs to take no arguments and has to return void or SetupResult. " + "The passed handler doesn't fulfill these requirements."); return [=] { - if constexpr (isDynamic) + if constexpr (isS) return std::invoke(handler); std::invoke(handler); return SetupResult::Continue; }; }; - template + template static GroupDoneHandler wrapGroupDone(Handler &&handler) { - static constexpr bool isBD // stands for [B]ool, [D]oneWith - = std::is_invocable_r_v, DoneWith>; - static constexpr bool isB - = std::is_invocable_r_v>; - static constexpr bool isVD // stands for [V]oid, [D]oneWith - = std::is_invocable_r_v, DoneWith>; - static constexpr bool isV - = std::is_invocable_r_v>; - static constexpr bool isInvocable = isBD || isB || isVD || isV; - - static_assert(isInvocable, - "Group done handler needs to take (DoneWith) or (void) " - "as arguments and has to return void or bool. " - "The passed handler doesn't fulfill these requirements."); + // B, V, D stands for: [B]ool, [V]oid, [D]oneWith + static constexpr bool isBD = isInvocable(); + static constexpr bool isB = isInvocable(); + static constexpr bool isVD = isInvocable(); + static constexpr bool isV = isInvocable(); + static_assert(isBD || isB || isVD || isV, + "Group done handler needs to take (DoneWith) or (void) as an argument and has to " + "return void or bool. The passed handler doesn't fulfill these requirements."); return [=](DoneWith result) { if constexpr (isBD) return std::invoke(handler, result); @@ -338,24 +342,28 @@ public: class TASKING_EXPORT Sync final : public GroupItem { public: - template - Sync(Function &&function) { addChildren({init(std::forward(function))}); } + template + Sync(Handler &&handler) { + addChildren({ onGroupSetup(wrapHandler(std::forward(handler))) }); + } private: - template - static GroupItem init(Function &&function) { - constexpr bool isInvocable = std::is_invocable_v>; - static_assert(isInvocable, - "Sync element: The synchronous function can't take any arguments."); - constexpr bool isBool = std::is_same_v>>; - constexpr bool isVoid = std::is_same_v>>; - static_assert(isBool || isVoid, - "Sync element: The synchronous function has to return void or bool."); - if constexpr (isBool) { - return onGroupSetup([function] { return function() ? SetupResult::StopWithSuccess - : SetupResult::StopWithError; }); - } - return onGroupSetup([function] { function(); return SetupResult::StopWithSuccess; }); + template + static GroupSetupHandler wrapHandler(Handler &&handler) { + // B, V stands for: [B]ool, [V]oid + static constexpr bool isB = isInvocable(); + static constexpr bool isV = isInvocable(); + static_assert(isB || isV, + "Sync handler needs to take no arguments and has to return void or bool. " + "The passed handler doesn't fulfill these requirements."); + return [=] { + if constexpr (isB) { + return std::invoke(handler) ? SetupResult::StopWithSuccess + : SetupResult::StopWithError; + } + std::invoke(handler); + return SetupResult::StopWithSuccess; + }; }; }; @@ -401,49 +409,39 @@ public: } private: - template + template static GroupItem::TaskSetupHandler wrapSetup(Handler &&handler) { if constexpr (std::is_same_v) return {}; // When user passed {} for the setup handler. - static constexpr bool isDynamic - = std::is_same_v, Task &>>; - constexpr bool isVoid - = std::is_same_v, Task &>>; - static_assert(isDynamic || isVoid, - "Task setup handler needs to take (Task &) as an argument and has to return " - "void or SetupResult. The passed handler doesn't fulfill these requirements."); + // S, V stands for: [S]etupResult, [V]oid + static constexpr bool isS = isInvocable(); + static constexpr bool isV = isInvocable(); + static_assert(isS || isV, + "Task setup handler needs to take (Task &) as an argument and has to return void or " + "SetupResult. The passed handler doesn't fulfill these requirements."); return [=](TaskInterface &taskInterface) { Adapter &adapter = static_cast(taskInterface); - if constexpr (isDynamic) + if constexpr (isS) return std::invoke(handler, *adapter.task()); std::invoke(handler, *adapter.task()); return SetupResult::Continue; }; }; - template + template static GroupItem::TaskDoneHandler wrapDone(Handler &&handler) { if constexpr (std::is_same_v) return {}; // When user passed {} for the done handler. - static constexpr bool isBTD // stands for [B]ool, [T]ask, [D]oneWith - = std::is_invocable_r_v, const Task &, DoneWith>; - static constexpr bool isBT - = std::is_invocable_r_v, const Task &>; - static constexpr bool isBD - = std::is_invocable_r_v, DoneWith>; - static constexpr bool isB - = std::is_invocable_r_v>; - static constexpr bool isVTD // stands for [V]oid, [T]ask, [D]oneWith - = std::is_invocable_r_v, const Task &, DoneWith>; - static constexpr bool isVT - = std::is_invocable_r_v, const Task &>; - static constexpr bool isVD - = std::is_invocable_r_v, DoneWith>; - static constexpr bool isV - = std::is_invocable_r_v>; - static constexpr bool isInvocable = isBTD || isBT || isBD || isB - || isVTD || isVT || isVD || isV; - static_assert(isInvocable, + // B, V, T, D stands for: [B]ool, [V]oid, [T]ask, [D]oneWith + static constexpr bool isBTD = isInvocable(); + static constexpr bool isBT = isInvocable(); + static constexpr bool isBD = isInvocable(); + static constexpr bool isB = isInvocable(); + static constexpr bool isVTD = isInvocable(); + static constexpr bool isVT = isInvocable(); + static constexpr bool isVD = isInvocable(); + static constexpr bool isV = isInvocable(); + static_assert(isBTD || isBT || isBD || isB || isVTD || isVT || isVD || isV, "Task done handler needs to take (const Task &, DoneWith), (const Task &), " "(DoneWith) or (void) as arguments and has to return void or bool. " "The passed handler doesn't fulfill these requirements."); @@ -503,23 +501,19 @@ public: template void onStorageSetup(const TreeStorage &storage, StorageHandler &&handler) { - constexpr bool isInvocable = std::is_invocable_v, - StorageStruct &>; - static_assert(isInvocable, + static_assert(std::is_invocable_v, StorageStruct &>, "Storage setup handler needs to take (Storage &) as an argument. " - "The passed handler doesn't fulfill these requirements."); + "The passed handler doesn't fulfill this requirement."); setupStorageHandler(storage, wrapHandler(std::forward(handler)), {}); } template void onStorageDone(const TreeStorage &storage, StorageHandler &&handler) { - constexpr bool isInvocable = std::is_invocable_v, - const StorageStruct &>; - static_assert(isInvocable, + static_assert(std::is_invocable_v, const StorageStruct &>, "Storage done handler needs to take (const Storage &) as an argument. " - "The passed handler doesn't fulfill these requirements."); - setupStorageHandler(storage, - {}, wrapHandler(std::forward(handler))); + "The passed handler doesn't fulfill this requirement."); + setupStorageHandler(storage, {}, + wrapHandler(std::forward(handler))); } signals: @@ -536,7 +530,7 @@ private: template StorageVoidHandler wrapHandler(StorageHandler &&handler) { return [=](void *voidStruct) { - StorageStruct *storageStruct = static_cast(voidStruct); + auto *storageStruct = static_cast(voidStruct); std::invoke(handler, *storageStruct); }; } diff --git a/tests/auto/solutions/tasking/tst_tasking.cpp b/tests/auto/solutions/tasking/tst_tasking.cpp index ed10565092b..67442fde1bd 100644 --- a/tests/auto/solutions/tasking/tst_tasking.cpp +++ b/tests/auto/solutions/tasking/tst_tasking.cpp @@ -139,28 +139,89 @@ void tst_Tasking::validConstructs() // When turning each of below blocks on, you should see the specific compiler error message. + // Sync handler needs to take no arguments and has to return void or bool. #if 0 - { - // "Sync element: The synchronous function has to return void or bool." - const auto setupSync = [] { return 3; }; - const Sync sync(setupSync); - } + Sync([] { return 7; }); +#endif +#if 0 + Sync([](int) { }); +#endif +#if 0 + Sync([](int) { return true; }); #endif + // Group setup handler needs to take no arguments and has to return void or SetupResult. #if 0 - { - // "Sync element: The synchronous function can't take any arguments." - const auto setupSync = [](int) { }; - const Sync sync(setupSync); - } + onGroupSetup([] { return 7; }); +#endif +#if 0 + onGroupSetup([](int) { }); #endif + // Group done handler needs to take (DoneWith) or (void) as an argument and has to + // return void or bool. #if 0 - { - // "Sync element: The synchronous function can't take any arguments." - const auto setupSync = [](int) { return true; }; - const Sync sync(setupSync); - } + onGroupDone([] { return 7; }); +#endif +#if 0 + onGroupDone([](DoneWith) { return 7; }); +#endif +#if 0 + onGroupDone([](int) { }); +#endif +#if 0 + onGroupDone([](DoneWith, int) { }); +#endif + + // Task setup handler needs to take (Task &) as an argument and has to return void or + // SetupResult. +#if 0 + TestTask([] {}); +#endif +#if 0 + TestTask([] { return 7; }); +#endif +#if 0 + TestTask([](TaskObject &) { return 7; }); +#endif +#if 0 + TestTask([](TaskObject &, int) { return SetupResult::Continue; }); +#endif + + // Task done handler needs to take (const Task &, DoneWith), (const Task &), + // (DoneWith) or (void) as arguments and has to return void or bool. +#if 0 + TestTask({}, [](const TaskObject &, DoneWith) { return 7; }); +#endif +#if 0 + TestTask({}, [](const TaskObject &) { return 7; }); +#endif +#if 0 + TestTask({}, [] { return 7; }); +#endif +#if 0 + TestTask({}, [](const TaskObject &, DoneWith, int) {}); +#endif +#if 0 + TestTask({}, [](const TaskObject &, int) {}); +#endif +#if 0 + TestTask({}, [](DoneWith, int) {}); +#endif +#if 0 + TestTask({}, [](int) {}); +#endif +#if 0 + TestTask({}, [](const TaskObject &, DoneWith, int) { return true; }); +#endif +#if 0 + TestTask({}, [](const TaskObject &, int) { return true; }); +#endif +#if 0 + TestTask({}, [](DoneWith, int) { return true; }); +#endif +#if 0 + TestTask({}, [](int) { return true; }); #endif }