-
Notifications
You must be signed in to change notification settings - Fork 1.7k
PPLX move-only task parameter support #1231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
(functor copy count reduced from 7 to 5)
…ut compiler errors. Also static_assert for task result type check added.
…pass void-result tce only into void-result task. Also adding tests for these cases.
…etween task<T> and task<void> classes.
…) function by introducing forwarding-reference parameter.
…or from details::_FilterValidTaskType() function, so initial tasks can be constructed from move-only objects.
`TestTasks_move_only_then` test logic moved to `create_task_with_move_only_continuation` test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmmm I'm not sure how reasonable this is; we generally want pplx to have the exact same API as PPL, and PPL can never take such a change due to ABI restrictions (it often puts the callables into a std::function).
@@ -3066,25 +3081,58 @@ auto _IsValidTaskCtor(_Ty _Param, int, int, ...) | |||
-> decltype(_Param.set(stdx::declval<_ReturnType>()), std::true_type()); | |||
|
|||
template<typename _ReturnType, typename _Ty> | |||
auto _IsValidTaskCtor(_Ty _Param, int, ...) -> decltype(_Param.set(), std::true_type()); | |||
auto _IsValidTaskCtor(_Ty _Param, int, ...) | |||
-> decltype(_Param.set(), typename std::enable_if<std::is_same<_ReturnType, void>::value>::type(), std::true_type()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change appears to rely on expression SFINAE which is not safe to use on one of our supported compilers, VS2015.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that existing logic like decltype(_Param.set(), /*...*/)
, which check a method existence, already use expression SFINAE. So I decided that this change should be safe. Anyway, I just tried to compile it in VS2015 (update 3) with forced PPLX, and it seems to work there.
Furthermore, VS2015 is not using PPLX by default, and this code enabled only for PPLX.
Release/include/pplx/pplxtasks.h
Outdated
template<typename _Ty, typename _ReturnType, typename = | ||
typename std::enable_if<!std::is_base_of<task<_ReturnType>, _Ty>::value>::type | ||
> | ||
struct _EnableIfNotTaskRet |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You probably want to derive from enable_if rather than making formation of _EnableIfNotTaskRet itself impossible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Release/include/pplx/pplxtasks.h
Outdated
@@ -4391,11 +4408,11 @@ class task<void> | |||
/// Runtime)"/>.</para> | |||
/// </remarks> | |||
/**/ | |||
template<typename _Ty> | |||
template<typename _Ty, typename = typename details::_EnableIfNotTaskRet<typename std::decay<_Ty>::type, void>> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Conventionally, preventing this from being a special member function should use the injected class name; e.g. `typename = enable_if_t<is_same_v<task, decay_t<_Ty>>>"
(Occurs elsewhere)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exactly what _EnableIfNotTaskRet
doing: checks that _Ty
is not derived from task<_ReturnType>
(is_base_of
check includes is_same
logic in this case). So we can catch that tricky case when _Ty
is not a task
class itself, but its child class, when compiler may decide to use this forwarding-reference overload instead of copy- or move-constructor.
} | ||
#endif // !(defined(_MSC_VER) && (_MSC_VER >= 1800) && !CPPREST_FORCE_PPLX) | ||
|
||
//TODO: tests for _AsyncTaskCtorArgsValidator (__cplusplus_winrt only) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't check in TODO comments; feel free to file an 'XXX should be tested' issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that __cplusplus_winrt
stuff is not presented in tests at all, so I removed this TODO (6d8c603)
VERIFY_ARE_EQUAL(t2.get(), 22); | ||
} | ||
|
||
#if !(defined(_MSC_VER) && (_MSC_VER >= 1800) && !CPPREST_FORCE_PPLX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If _MSC_VER is not defined, then it can't be defined to greater than 1800. Perhaps demorgan?
#if !defined(_MSC_VER) || CPPREST_FORCE_PPLX
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But when _MSC_VER
is defined, it can be less than 1800, and this should make this #if
work.
P.S. This all is just opposite condition from the beginning of the pplxtasks.h file, where choose between PPL and pplx is made.
I tried to save existing compatibility conditions. And I used interface deviations brought by #47 as a reference. That is, when you can use #47's stuff, you can use this pull-request's stuff, and vice-versa. The only difference in place where movable-only functor can appear: continuation in case of #47 and initial task in case of current pull-request. |
…le_if`. Plus, fixing GCC compiling error related to `_EnableIfNotTaskRet` using.
All failed tests throws exception |
I'm sorry but as I indicated, for API compatibility reasons between PPL and PPLX I don't think I'm able to merge this :( |
It is possible now to pass move-only objects as task parameter to the
pplx::task
constructor and to thepplx::create_task()
function. So, code below is compilable now:Also, optimization comes as a free bonus, since we don't copy task parameter. For example, code below:
v
object;v
object.Another minor interface refactor - redundant
pplx::task
constructor has been removed for better match withpplx::create_task()
overloads.This pull request is similar to #47 change. And like in #47 change, all pplx-specific tests were placed under corresponding
#ifdef
.Checked in GCC 7.4.0 and MSVC2017 (both native windows ppl implementation, and forced pplx).