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
Turn class templates into a member classes of class templates to further narrow scope of ADL #83
Conversation
…tion-state types as non-template classmembers of a class template to avoid template parametersfrom becoming associated namespaces.
Not quite done yet, but getting there. |
template<> | ||
struct _fn::_impl<false> { | ||
template <typename Sender> | ||
auto operator()(Sender&& predecessor) const |
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 seem to be inconsistent with the naming of the input sender.
We use 'sender', 'source' and 'predecessor' in various places.
Ideally we'd be consistent. Any preferences?
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.
No strong feelings.
callback_.destruct(); | ||
if constexpr (is_stop_never_possible_v< | ||
stop_token_type_t<Receiver&>>) { | ||
unifex::set_value(std::move(receiver_)); |
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 just noticed that this call to set_value() could potentially be throwing (since we don't require that set_value() customisations are noexcept any more).
We probably need to do a pass through libunifex to pick up calls to set_value() and wrap them in try/catch if they are not noexcept.
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'll leave it for now.
…uence(). Make CPO and sender/receiver arguments deduced and then constrain to SFINAE out if the types don't match exactly. Also modify handling of sequence() overload for 3 or more parameters to avoid infinite recursion of function instantiation under msvc by adding an explicit third argument so that the overload would not be considered for the recrusive call to sequence() with two argments.
…nsform(). Make CPO and sender/receiver arguments deduced and then constrain to SFINAE out if the types don't match exactly.
…n_all(). Make CPO and sender/receiver arguments deduced and then constrain to SFINAE out if the types don't match exactly.
…, Args...> on finally(), sequence() and when_all(). This allows examples/async_trace.cpp to build under msvc.
MSVC was too eagerly istantiating tag_invoke() overloads where there were non-deduced paramters (like a CPO or receiver parameter). Now make these deduced parameters and explicitly exclude these overloads using enable_if so that the examples/materialize builds under msvc.
…late function instantiation. Added UNIFEX_[DECLARE/USE]_NON_DEDUCED_TYPE(NAME, TYPE). On MSVC this lowers to enable_if-based SFINAE. On other compilers this lowers to a non-template argument. Updated the materialize/dematerialize algorithms to use these macros where appropriate.
include/unifex/any_unique.hpp
Outdated
struct type { | ||
private: | ||
template <typename T> | ||
static void* get_object_address(T&& t) { |
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.
Should this be noexcept?
include/unifex/async_mutex.hpp
Outdated
}; | ||
template <typename Receiver> | ||
using operation = typename _op<std::decay_t<Receiver>>::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.
We are inconsistent with use of decay_t vs remove_cvref_t when decaying the Receiver types.
Should always just use remove_cvref_t?
template <bool> | ||
struct _impl { | ||
template <typename Sender> | ||
constexpr blocking_kind operator()(const Sender&) noexcept { | ||
return blocking_kind::maybe; | ||
} | ||
}; |
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.
Should be private:
?
include/unifex/materialize.hpp
Outdated
typename Func, | ||
UNIFEX_DECLARE_NON_DEDUCED_TYPE(CPO, tag_t<visit_continuations>), | ||
UNIFEX_DECLARE_NON_DEDUCED_TYPE(R, receiver), | ||
typename Func> | ||
UNIFEX_DECLARE_NON_DEDUCED_TYPE(R, receiver)> |
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.
Why was the change to put Func first needed?
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.
Because clang was not allowing a non-defaulted template parameter to follow ones that had defaults.
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.
That would be the case for classes, but I didn't think it was the case for functions where template parameters can be deduced.
eg. see https://godbolt.org/z/oQmQ_d which has leading defaulted templated args followed by non-defaulted-but-deduced template args.
auto operator co_await(Sender&& sender) { | ||
return sender_awaiter<Sender, Result>{(Sender&&)sender}; | ||
return _coroutine::sender_awaiter<Sender, Result>{(Sender&&)sender}; | ||
} |
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 wonder if moving the existing sender types out of the unifex
namespace and into child namespaces will mean that this operator co_await()
overload is not found for some operations...
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.
Probably so, but that was always going to be the case. We expect others to define sender types in their namespace. It's one of the reasons why sender_base
exists in the P0443 design.
include/unifex/single.hpp
Outdated
inline constexpr struct _fn { | ||
template <typename Sender> | ||
auto operator()(Sender&& sender) const { | ||
return _single::stream<std::remove_cvref_t<Sender>>{(Sender&&)sender}; |
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 are double-applying the std::remove_cvref_t both here and in the _single::stream alias.
@@ -37,5 +37,8 @@ class single_thread_context { | |||
return loop_.get_scheduler(); | |||
} | |||
}; | |||
} // namespace _single_thread | |||
|
|||
using single_thread_context = _single_thread::context; |
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.
Do we need to ADL-isolate this class as it doesn't customise any ADL-calls?
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.
Probably not strictly necessary given the other ADL mitigations we have in place, but defining types in ADL-blocking namespaces is a good habit, and I would rather we are consistent about it.
include/unifex/stop_immediately.hpp
Outdated
template callback_type<cancel_next_callback>> | ||
stopCallback_; | ||
|
||
using ST = stop_token_type_t<Receiver&>; |
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.
Can we move this type-alias further up so it can be used in the declaration of the stopCallback_
member?
include/unifex/stop_immediately.hpp
Outdated
template<typename SourceStream, typename... Values> | ||
using stop_immediately_stream = | ||
_stop_immediately::stream<SourceStream, Values...>; |
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.
Sometimes you've been putting the aliases for the stream classes inside the impl namespace (e.g. see single.hpp
) and sometimes in the public unifex
namespace (like here).
We should be consistent about whether the sender/stream types are public types or not (my preference is to keep them private for now)
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.
In some places, the class name is the API (like never_stream
). We could change this to be consistent and make never_stream
a CPO that returns a _never::stream
, but I think this diff is big enough.
EDIT: ... or never_stream
could be an inline constexpr
object of type _never::stream
.
We also need to update the |
The _inline symbol is a keyword under msvc.
Msvc wantscomplex constexpr expressions used as template arguments to be enclosed in parentheses.
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.
LGTM - we can address the remaining bits in future PRs.
No description provided.