Skip to content
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

constexpr INVOKE and related utilities #703

Merged
merged 33 commits into from
Jul 3, 2020
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1a1c6c8
Implement P1065R2
AdamBucior Apr 10, 2020
b810961
clang-format
AdamBucior Apr 10, 2020
0df32eb
string_view is not available before C++17
AdamBucior Apr 10, 2020
e8b5212
use using instead of #define
AdamBucior Apr 10, 2020
e0e6e3e
remove noexcept from _Not_fn's copy and move constructors
AdamBucior Apr 10, 2020
e633272
Comment indentation
AdamBucior Apr 11, 2020
7a0734e
Remove strengthened comment
AdamBucior Apr 11, 2020
33d6da3
Remove strengthened comment
AdamBucior Apr 11, 2020
bc84c1c
Remove strengthened comment
AdamBucior Apr 11, 2020
d7dd3c1
Remove strengthened comment
AdamBucior Apr 11, 2020
e23307f
Remove strengthened comment
AdamBucior Apr 11, 2020
16273d5
Part of changes requested by Stephan
AdamBucior Apr 11, 2020
0356a9a
noexcept for _Binder::operator()
AdamBucior Apr 11, 2020
09521f8
clang-format
AdamBucior Apr 11, 2020
a2d07e1
pack expansion cannot be used as argument for non-pack parameter of a…
AdamBucior Apr 11, 2020
9bfd797
Some more noexcept tests
AdamBucior Apr 11, 2020
73cd5a6
Merge branch 'master' into constexpr-invoke
AdamBucior Apr 30, 2020
17b1349
clang-format
AdamBucior Apr 30, 2020
7cff843
Merge branch 'master' into constexpr-invoke
AdamBucior Apr 30, 2020
87d0d8d
Merge branch 'master' into constexpr-invoke
StephanTLavavej May 9, 2020
970034c
Merge branch 'master' into pr703
CaseyCarter May 27, 2020
c9a9011
Workaround EDG bug
CaseyCarter May 28, 2020
c62af1c
Update __cpp_lib_constexpr_functional
CaseyCarter May 28, 2020
6594ed4
Workaround EDG bug
CaseyCarter May 28, 2020
0f9fb59
Test bind nothrowness in C++17
AdamBucior May 28, 2020
6af2854
Move _Invoker_ret to <functional>
AdamBucior May 28, 2020
62da136
Merge branch 'master' into constexpr-invoke
AdamBucior May 30, 2020
0d3d972
Merge branch 'master' into constexpr-invoke
StephanTLavavej Jun 26, 2020
c4d829a
Merge branch 'master' into constexpr-invoke
StephanTLavavej Jul 2, 2020
1842d3c
Apply suggestions from code review
AdamBucior Jul 2, 2020
fe7a553
Follow the constexpr explicit convention
AdamBucior Jul 2, 2020
4811233
More tests for conditionally noexcept bind().
StephanTLavavej Jul 2, 2020
fce7580
Simplify _Invoker_ret specializations.
StephanTLavavej Jul 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 73 additions & 39 deletions stl/inc/functional
Original file line number Diff line number Diff line change
Expand Up @@ -643,18 +643,18 @@ private:
_Memptr _Pm;

public:
explicit _Mem_fn(_Memptr _Val) noexcept : _Pm(_Val) {}
constexpr explicit _Mem_fn(_Memptr _Val) noexcept : _Pm(_Val) {}

template <class... _Types>
auto operator()(_Types&&... _Args) const
noexcept(noexcept(_STD invoke(_Pm, _STD forward<_Types>(_Args)...))) // strengthened
-> decltype(_STD invoke(_Pm, _STD forward<_Types>(_Args)...)) {
_CONSTEXPR20 auto operator()(_Types&&... _Args) const
noexcept(noexcept(_STD invoke(_Pm, _STD forward<_Types>(_Args)...)))
-> decltype(_STD invoke(_Pm, _STD forward<_Types>(_Args)...)) {
return _STD invoke(_Pm, _STD forward<_Types>(_Args)...);
}
};

template <class _Rx, class _Ty>
_NODISCARD _Mem_fn<_Rx _Ty::*> mem_fn(_Rx _Ty::*_Pm) noexcept {
_NODISCARD _CONSTEXPR20 _Mem_fn<_Rx _Ty::*> mem_fn(_Rx _Ty::*_Pm) noexcept {
return _Mem_fn<_Rx _Ty::*>(_Pm);
}

Expand All @@ -671,43 +671,44 @@ private:

public:
template <class _Callable, class _Tag, enable_if_t<is_same_v<_Tag, _Not_fn_tag>, int> = 0>
explicit _Not_fn(_Callable&& _Obj, _Tag) noexcept(is_nothrow_constructible_v<_Decayed, _Callable>) // strengthened
constexpr explicit _Not_fn(_Callable&& _Obj, _Tag) noexcept(
is_nothrow_constructible_v<_Decayed, _Callable>) // strengthened
: _Mybase(_STD forward<_Callable>(_Obj)) {} // store a callable object

_Not_fn(const _Not_fn&) = default;
_Not_fn(_Not_fn&&) = default;
constexpr _Not_fn(const _Not_fn&) = default;
constexpr _Not_fn(_Not_fn&&) = default;

template <class... _Types>
auto operator()(_Types&&... _Args) & noexcept(
noexcept(!_STD invoke(this->_Get_val(), _STD forward<_Types>(_Args)...))) // strengthened
_CONSTEXPR20 auto operator()(_Types&&... _Args) & noexcept(
noexcept(!_STD invoke(this->_Get_val(), _STD forward<_Types>(_Args)...)))
-> decltype(!_STD declval<invoke_result_t<_Decayed&, _Types...>>()) {
return !_STD invoke(this->_Get_val(), _STD forward<_Types>(_Args)...);
}

template <class... _Types>
auto operator()(_Types&&... _Args) const& noexcept(noexcept(!_STD invoke(this->_Get_val(),
_STD forward<_Types>(_Args)...))) // strengthened
_CONSTEXPR20 auto operator()(_Types&&... _Args) const& noexcept(
noexcept(!_STD invoke(this->_Get_val(), _STD forward<_Types>(_Args)...)))
-> decltype(!_STD declval<invoke_result_t<const _Decayed&, _Types...>>()) {
return !_STD invoke(this->_Get_val(), _STD forward<_Types>(_Args)...);
}

template <class... _Types>
auto operator()(_Types&&... _Args) && noexcept(noexcept(!_STD invoke(_STD move(this->_Get_val()),
_STD forward<_Types>(_Args)...))) // strengthened
_CONSTEXPR20 auto operator()(_Types&&... _Args) && noexcept(
noexcept(!_STD invoke(_STD move(this->_Get_val()), _STD forward<_Types>(_Args)...)))
-> decltype(!_STD declval<invoke_result_t<_Decayed, _Types...>>()) {
return !_STD invoke(_STD move(this->_Get_val()), _STD forward<_Types>(_Args)...);
}

template <class... _Types>
auto operator()(_Types&&... _Args) const&& noexcept(noexcept(!_STD invoke(_STD move(this->_Get_val()),
_STD forward<_Types>(_Args)...))) // strengthened
_CONSTEXPR20 auto operator()(_Types&&... _Args) const&& noexcept(
noexcept(!_STD invoke(_STD move(this->_Get_val()), _STD forward<_Types>(_Args)...)))
-> decltype(!_STD declval<invoke_result_t<const _Decayed, _Types...>>()) {
return !_STD invoke(_STD move(this->_Get_val()), _STD forward<_Types>(_Args)...);
}
};

template <class _Callable>
_NODISCARD _Not_fn<decay_t<_Callable>> not_fn(_Callable&& _Obj) noexcept(
_NODISCARD _CONSTEXPR20 _Not_fn<decay_t<_Callable>> not_fn(_Callable&& _Obj) noexcept(
is_nothrow_constructible_v<decay_t<_Callable>, _Callable>) /* strengthened */ {
// wrap a callable object to be negated
return _Not_fn<decay_t<_Callable>>(_STD forward<_Callable>(_Obj), _Not_fn_tag{});
Expand Down Expand Up @@ -1334,30 +1335,35 @@ struct _Select_fixer;
template <class _Cv_TiD>
struct _Select_fixer<_Cv_TiD, true, false, 0> { // reference_wrapper fixer
template <class _Untuple>
static auto _Fix(_Cv_TiD& _Tid, _Untuple &&) -> typename _Cv_TiD::type& { // unwrap a reference_wrapper
static constexpr auto _Fix(_Cv_TiD& _Tid, _Untuple&&) noexcept -> typename _Cv_TiD::type& {
// unwrap a reference_wrapper
return _Tid.get();
}
};

template <class _Cv_TiD>
struct _Select_fixer<_Cv_TiD, false, true, 0> { // nested bind fixer
template <class _Untuple, size_t... _Jx>
static auto _Apply(_Cv_TiD& _Tid, _Untuple&& _Ut,
index_sequence<_Jx...>) -> decltype(_Tid(_STD get<_Jx>(_STD move(_Ut))...)) { // call a nested bind expression
static constexpr auto _Apply(_Cv_TiD& _Tid, _Untuple&& _Ut, index_sequence<_Jx...>) noexcept(
noexcept(_Tid(_STD get<_Jx>(_STD move(_Ut))...))) -> decltype(_Tid(_STD get<_Jx>(_STD move(_Ut))...)) {
// call a nested bind expression
return _Tid(_STD get<_Jx>(_STD move(_Ut))...);
}

template <class _Untuple>
static auto _Fix(_Cv_TiD& _Tid, _Untuple&& _Ut) -> decltype(
_Apply(_Tid, _STD move(_Ut), make_index_sequence<tuple_size_v<_Untuple>>{})) { // call a nested bind expression
static constexpr auto _Fix(_Cv_TiD& _Tid, _Untuple&& _Ut) noexcept(
noexcept(_Apply(_Tid, _STD move(_Ut), make_index_sequence<tuple_size_v<_Untuple>>{})))
-> decltype(_Apply(_Tid, _STD move(_Ut), make_index_sequence<tuple_size_v<_Untuple>>{})) {
// call a nested bind expression
return _Apply(_Tid, _STD move(_Ut), make_index_sequence<tuple_size_v<_Untuple>>{});
}
};

template <class _Cv_TiD>
struct _Select_fixer<_Cv_TiD, false, false, 0> { // identity fixer
template <class _Untuple>
static _Cv_TiD& _Fix(_Cv_TiD& _Tid, _Untuple&&) { // pass a bound argument as an lvalue (important!)
static constexpr _Cv_TiD& _Fix(_Cv_TiD& _Tid, _Untuple&&) noexcept {
// pass a bound argument as an lvalue (important!)
return _Tid;
}
};
Expand All @@ -1367,23 +1373,26 @@ struct _Select_fixer<_Cv_TiD, false, false, _Jx> { // placeholder fixer
static_assert(_Jx > 0, "invalid is_placeholder value");

template <class _Untuple>
static auto _Fix(_Cv_TiD&, _Untuple&& _Ut)
static constexpr auto _Fix(_Cv_TiD&, _Untuple&& _Ut) noexcept
-> decltype(_STD get<_Jx - 1>(_STD move(_Ut))) { // choose the Jth unbound argument (1-based indexing)
return _STD get<_Jx - 1>(_STD move(_Ut));
}
};

template <class _Cv_TiD, class _Untuple>
auto _Fix_arg(_Cv_TiD& _Tid, _Untuple&& _Ut)
constexpr auto _Fix_arg(_Cv_TiD& _Tid, _Untuple&& _Ut) noexcept(
noexcept(_Select_fixer<_Cv_TiD>::_Fix(_Tid, _STD move(_Ut))))
-> decltype(_Select_fixer<_Cv_TiD>::_Fix(_Tid, _STD move(_Ut))) { // translate an argument for bind
return _Select_fixer<_Cv_TiD>::_Fix(_Tid, _STD move(_Ut));
}

// FUNCTION TEMPLATE _Call_binder
template <class _Ret, size_t... _Ix, class _Cv_FD, class _Cv_tuple_TiD, class _Untuple>
auto _Call_binder(_Invoker_ret<_Ret>, index_sequence<_Ix...>, _Cv_FD& _Obj, _Cv_tuple_TiD& _Tpl, _Untuple&& _Ut)
-> decltype(_Invoker_ret<_Ret>::_Call(
_Obj, _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...)) { // bind() and bind<R>() invocation
_CONSTEXPR20 auto _Call_binder(_Invoker_ret<_Ret>, index_sequence<_Ix...>, _Cv_FD& _Obj, _Cv_tuple_TiD& _Tpl,
_Untuple&& _Ut) noexcept(noexcept(_Invoker_ret<_Ret>::_Call(_Obj,
_Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...)))
-> decltype(_Invoker_ret<_Ret>::_Call(_Obj, _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...)) {
// bind() and bind<R>() invocation
return _Invoker_ret<_Ret>::_Call(_Obj, _Fix_arg(_STD get<_Ix>(_Tpl), _STD move(_Ut))...);
}

Expand Down Expand Up @@ -1413,30 +1422,55 @@ private:
_Compressed_pair<_First, _Second> _Mypair;

public:
explicit _Binder(_Fx&& _Func, _Types&&... _Args)
constexpr explicit _Binder(_Fx&& _Func, _Types&&... _Args)
: _Mypair(_One_then_variadic_args_t{}, _STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...) {}

#define _BINDER_OPERATOR(CONST_OPT) \
template <class... _Unbound> \
auto operator()(_Unbound&&... _Unbargs) CONST_OPT->decltype(_Call_binder(_Invoker_ret<_Ret>(), _Seq{}, \
_Mypair._Get_first(), _Mypair._Myval2, _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))) { \
return _Call_binder(_Invoker_ret<_Ret>(), _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, \
_STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...)); \
#define _CALL_BINDER \
_Call_binder(_Invoker_ret<_Ret>(), _Seq{}, _Mypair._Get_first(), _Mypair._Myval2, \
AdamBucior marked this conversation as resolved.
Show resolved Hide resolved
_STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))

#ifdef __EDG__ // TRANSITION, VSO-1132105
template <class... _Unbound>
_CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_Call_binder(_Invoker_ret<_Ret>(), _Seq{},
AdamBucior marked this conversation as resolved.
Show resolved Hide resolved
_STD declval<_First&>(), _STD declval<_Second&>(), _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))))
-> decltype(_Call_binder(_Invoker_ret<_Ret>(), _Seq{}, _STD declval<_First&>(), _STD declval<_Second&>(),
AdamBucior marked this conversation as resolved.
Show resolved Hide resolved
_STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))) {
return _CALL_BINDER;
}

template <class... _Unbound>
_CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) const
noexcept(noexcept(_Call_binder(_Invoker_ret<_Ret>(), _Seq{}, _STD declval<const _First&>(),
AdamBucior marked this conversation as resolved.
Show resolved Hide resolved
_STD declval<const _Second&>(), _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))))
-> decltype(_Call_binder(_Invoker_ret<_Ret>(), _Seq{}, _STD declval<const _First&>(),
AdamBucior marked this conversation as resolved.
Show resolved Hide resolved
_STD declval<const _Second&>(), _STD forward_as_tuple(_STD forward<_Unbound>(_Unbargs)...))) {
return _CALL_BINDER;
}
#else // ^^^ workaround / no workaround vvv
template <class... _Unbound>
_CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) noexcept(noexcept(_CALL_BINDER)) -> decltype(_CALL_BINDER) {
return _CALL_BINDER;
}

template <class... _Unbound>
_CONSTEXPR20 auto operator()(_Unbound&&... _Unbargs) const noexcept(noexcept(_CALL_BINDER))
-> decltype(_CALL_BINDER) {
return _CALL_BINDER;
}
#endif // TRANSITION, VSO-1132105

_CLASS_DEFINE_CONST(_BINDER_OPERATOR)
#undef _BINDER_OPERATOR
#undef _CALL_BINDER
};

// FUNCTION TEMPLATE bind (implicit return type)
template <class _Fx, class... _Types>
_NODISCARD _Binder<_Unforced, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {
_NODISCARD _CONSTEXPR20 _Binder<_Unforced, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {
return _Binder<_Unforced, _Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
}

// FUNCTION TEMPLATE bind (explicit return type)
template <class _Ret, class _Fx, class... _Types>
_NODISCARD _Binder<_Ret, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {
_NODISCARD _CONSTEXPR20 _Binder<_Ret, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args) {
return _Binder<_Ret, _Fx, _Types...>(_STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...);
}

Expand Down
12 changes: 6 additions & 6 deletions stl/inc/memory
Original file line number Diff line number Diff line change
Expand Up @@ -1756,14 +1756,14 @@ private:

protected:
template <class _Other, enable_if_t<!is_same_v<_Remove_cvref_t<_Other>, _Ebco_base>, int> = 0>
explicit _Ebco_base(_Other&& _Val) noexcept(is_nothrow_constructible_v<_Ty, _Other>)
constexpr explicit _Ebco_base(_Other&& _Val) noexcept(is_nothrow_constructible_v<_Ty, _Other>)
: _Ty(_STD forward<_Other>(_Val)) {}

_Ty& _Get_val() noexcept {
constexpr _Ty& _Get_val() noexcept {
return *this;
}

const _Ty& _Get_val() const noexcept {
constexpr const _Ty& _Get_val() const noexcept {
return *this;
}
};
Expand All @@ -1775,14 +1775,14 @@ private:

protected:
template <class _Other, enable_if_t<!is_same_v<_Remove_cvref_t<_Other>, _Ebco_base>, int> = 0>
explicit _Ebco_base(_Other&& _Val) noexcept(is_nothrow_constructible_v<_Ty, _Other>)
constexpr explicit _Ebco_base(_Other&& _Val) noexcept(is_nothrow_constructible_v<_Ty, _Other>)
: _Myval(_STD forward<_Other>(_Val)) {}

_Ty& _Get_val() noexcept {
constexpr _Ty& _Get_val() noexcept {
return _Myval;
}

const _Ty& _Get_val() const noexcept {
constexpr const _Ty& _Get_val() const noexcept {
return _Myval;
}
};
Expand Down
Loading