Skip to content

Commit

Permalink
Merge pull request #85 from pfultz2/callable
Browse files Browse the repository at this point in the history
Callable
  • Loading branch information
pfultz2 committed Dec 17, 2015
2 parents 60e9b38 + 3454a17 commit fa265bb
Show file tree
Hide file tree
Showing 34 changed files with 653 additions and 292 deletions.
73 changes: 73 additions & 0 deletions doc/src/concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,79 @@ Given
|---------------|--------------------------|
| `f(identity)` | performs a function call |

Callable
--------

Is an object for which the `INVOKE` operation can be applied.

#### Requirements:

The type `T` satisfies `Callable` if

Given

* `f`, an object of type `const T`
* `Args...`, suitable list of argument types

The following expressions must be valid:

| Expression | Requirements |
|--------------------------------------|-------------------------------------------------------|
| `INVOKE(f, std::declval<Args>()...)` | the expression is well-formed in unevaluated context |

where `INVOKE(f, x, xs...)` is defined as follows:

* if `f` is a pointer to member function of class `T`:

- If `std::is_base_of<T, std::decay_t<decltype(x)>>()` is true, then `INVOKE(f, x, xs...)` is equivalent to `(x.*f)(xs...)`
- otherwise, if `std::decay_t<decltype(x)>` is a specialization of `std::reference_wrapper`, then `INVOKE(f, x, xs...)` is equivalent to `(x.get().*f)(xs...)`
- otherwise, if x does not satisfy the previous items, then `INVOKE(f, x, xs...)` is equivalent to `((*x).*f)(xs...)`.

* otherwise, if `f` is a pointer to data member of class `T`:

- If `std::is_base_of<T, std::decay_t<decltype(x)>>()` is true, then `INVOKE(f, x)` is equivalent to `x.*f`
- otherwise, if `std::decay_t<decltype(x)>` is a specialization of `std::reference_wrapper`, then `INVOKE(f, x)` is equivalent to `x.get().*f`
- otherwise, if `x` does not satisfy the previous items, then `INVOKE(f, x)` is equivalent to `(*x).*f`

* otherwise, `INVOKE(f, x, xs...)` is equivalent to `f(x, xs...)`

UnaryCallable
-------------

Is an object for which the `INVOKE` operation can be applied with one parameter.

#### Requirements:

* `Callable`

Given

* `f`, an object of type `const F`
* `arg`, a single argument

| Expression | Requirements |
|------------------|-------------------------------------------------------|
| `INVOKE(f, arg)` | the expression is well-formed in unevaluated context |

BinaryCallable
--------------------

Is an object for which the `INVOKE` operation can be applied with two parameters.

#### Requirements:

* `Callable`

Given

* `f`, an object of type `const F`
* `arg1`, a single argument
* `arg2`, a single argument

| Expression | Requirements |
|-------------------------|-------------------------------------------------------|
| `INVOKE(f, arg1, arg2)` | the expression is well-formed in unevaluated context |

Metafunction
------------

Expand Down
107 changes: 105 additions & 2 deletions fit/apply.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
///
/// F must be:
///
/// * [FunctionObject](concepts.md#functionobject)
/// * [Callable](concepts.md#callable)
///
/// Example
/// -------
Expand All @@ -52,14 +52,117 @@
#include <fit/detail/forward.h>
#include <fit/detail/static_const_var.h>


namespace fit {

namespace detail {
#if FIT_HAS_MANUAL_DEDUCTION || FIT_NO_EXPRESSION_SFINAE
struct apply_mem_fn
{
template<class...>
struct convertible_args;

template<class T, class U>
struct is_convertible_args;

template<class... Ts, class... Us>
struct is_convertible_args<convertible_args<Ts...>, convertible_args<Us...>>
: and_<std::is_convertible<Ts, Us>...>
{};

#define FIT_APPLY_MEM_FN_CALL(cv) \
template <class R, class Base, class Derived, class... Ts, class... Us, class=typename std::enable_if<and_< \
std::is_base_of<Base, typename std::decay<Derived>::type>, \
is_convertible_args<convertible_args<Us...>, convertible_args<Ts...>> \
>::value>::type> \
constexpr R operator()(R (Base::*mf)(Ts...) cv, Derived&& ref, Us &&... xs) const \
{ \
return (fit::forward<Derived>(ref).*mf)(fit::forward<Us>(xs)...); \
}
FIT_APPLY_MEM_FN_CALL()
FIT_APPLY_MEM_FN_CALL(const)
FIT_APPLY_MEM_FN_CALL(volatile)
FIT_APPLY_MEM_FN_CALL(const volatile)
};

struct apply_mem_data
{
template <class Base, class R, class Derived, class=typename std::enable_if<(
std::is_base_of<Base, typename std::decay<Derived>::type>::value
)>::type>
constexpr R operator()(R Base::*pmd, Derived&& ref) const
{
return fit::forward<Derived>(ref).*pmd;
}
};

template<class T, class U=decltype(*std::declval<T>())>
struct apply_deref
{ typedef U type; };

#endif

struct apply_f
{
#if FIT_HAS_MANUAL_DEDUCTION || FIT_NO_EXPRESSION_SFINAE
template<class F, class T, class... Ts, class=typename std::enable_if<(
std::is_member_function_pointer<typename std::decay<F>::type>::value
)>::type>
constexpr FIT_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<T>, id_<Ts>...)
operator()(F&& f, T&& obj, Ts&&... xs) const FIT_SFINAE_MANUAL_RETURNS
(
apply_mem_fn()(f, fit::forward<T>(obj), fit::forward<Ts>(xs)...)
);

template<class F, class T, class... Ts, class U=typename apply_deref<T>::type, class=typename std::enable_if<(
std::is_member_function_pointer<typename std::decay<F>::type>::value
)>::type>
constexpr FIT_SFINAE_MANUAL_RESULT(apply_mem_fn, id_<F>, id_<U>, id_<Ts>...)
operator()(F&& f, T&& obj, Ts&&... xs) const FIT_SFINAE_MANUAL_RETURNS
(
apply_mem_fn()(f, *fit::forward<T>(obj), fit::forward<Ts>(xs)...)
);

template<class F, class T, class=typename std::enable_if<(
std::is_member_object_pointer<typename std::decay<F>::type>::value
)>::type>
constexpr FIT_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<T>)
operator()(F&& f, T&& obj) const FIT_SFINAE_MANUAL_RETURNS
(
apply_mem_data()(f, fit::forward<T>(obj))
);

template<class F, class T, class U=typename apply_deref<T>::type, class=typename std::enable_if<(
std::is_member_object_pointer<typename std::decay<F>::type>::value
)>::type>
constexpr FIT_SFINAE_MANUAL_RESULT(apply_mem_data, id_<F>, id_<U>)
operator()(F&& f, T&& obj) const FIT_SFINAE_MANUAL_RETURNS
(
apply_mem_data()(f, *fit::forward<T>(obj))
);

#else

template <class Base, class T, class Derived>
constexpr auto operator()(T Base::*pmd, Derived&& ref) const
FIT_RETURNS(fit::forward<Derived>(ref).*pmd);

template <class PMD, class Pointer>
constexpr auto operator()(PMD&& pmd, Pointer&& ptr) const
FIT_RETURNS((*fit::forward<Pointer>(ptr)).*fit::forward<PMD>(pmd));

template <class Base, class T, class Derived, class... Args>
constexpr auto operator()(T Base::*pmf, Derived&& ref, Args&&... args) const
FIT_RETURNS((fit::forward<Derived>(ref).*pmf)(fit::forward<Args>(args)...));

template <class PMF, class Pointer, class... Args>
constexpr auto operator()(PMF&& pmf, Pointer&& ptr, Args&&... args) const
FIT_RETURNS(((*fit::forward<Pointer>(ptr)).*fit::forward<PMF>(pmf))(fit::forward<Args>(args)...));

#endif
template<class F, class... Ts>
constexpr FIT_SFINAE_RESULT(F, id_<Ts>...) operator()(F&& f, Ts&&... xs) const FIT_SFINAE_RETURNS
constexpr FIT_SFINAE_RESULT(F, id_<Ts>...)
operator()(F&& f, Ts&&... xs) const FIT_SFINAE_RETURNS
(
f(fit::forward<Ts>(xs)...)
);
Expand Down
11 changes: 6 additions & 5 deletions fit/apply_eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
///
/// F must be:
///
/// * [FunctionObject](concepts.md#functionobject)
/// * [Callable](concepts.md#callable)
///
/// Ts must be:
///
Expand All @@ -57,6 +57,7 @@
#include <fit/returns.h>
#include <fit/detail/forward.h>
#include <fit/detail/static_const_var.h>
#include <fit/apply.h>
#include <fit/eval.h>

#ifndef FIT_NO_ORDERD_BRACE_INIT
Expand Down Expand Up @@ -95,7 +96,7 @@ struct eval_helper
R result;

template<class F, class... Ts>
constexpr eval_helper(const F& f, Ts&&... xs) : result(f(fit::forward<Ts>(xs)...))
constexpr eval_helper(const F& f, Ts&&... xs) : result(apply(f, fit::forward<Ts>(xs)...))
{}

constexpr R get_result()
Expand All @@ -109,15 +110,15 @@ struct eval_helper<void>
{
int x;
template<class F, class... Ts>
constexpr eval_helper(const F& f, Ts&&... xs) : x(f(fit::forward<Ts>(xs)...), 0)
constexpr eval_helper(const F& f, Ts&&... xs) : x(apply(f, fit::forward<Ts>(xs)...), 0)
{}
};
#endif

struct apply_eval_f
{
template<class F, class... Ts, class R=decltype(
std::declval<const F&>()(fit::eval(std::declval<Ts>())...)
apply(std::declval<const F&>(), fit::eval(std::declval<Ts>())...)
),
class=typename std::enable_if<(!std::is_void<R>::value)>::type
>
Expand All @@ -134,7 +135,7 @@ struct apply_eval_f
}

template<class F, class... Ts, class R=decltype(
std::declval<const F&>()(fit::eval(std::declval<Ts>())...)
apply(std::declval<const F&>(), fit::eval(std::declval<Ts>())...)
),
class=typename std::enable_if<(std::is_void<R>::value)>::type
>
Expand Down
40 changes: 20 additions & 20 deletions fit/by.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@
///
/// Projection must be:
///
/// * [UnaryFunctionObject](concepts.md#unaryfunctionobject)
/// * [UnaryCallable](concepts.md#unarycallable)
/// * MoveConstructible
///
/// F must be:
///
/// * [FunctionObject](concepts.md#functionobject)
/// * [Callable](concepts.md#callable)
/// * MoveConstructible
///
/// Example
Expand All @@ -60,14 +60,14 @@
/// {}
/// int x;
/// };
/// assert(fit::by(std::mem_fn(&foo::x), _ + _)(foo(1), foo(2)) == 3);
/// assert(fit::by(&foo::x, _ + _)(foo(1), foo(2)) == 3);
///



#include <utility>
#include <fit/always.h>
#include <fit/detail/delegate.h>
#include <fit/detail/callable_base.h>
#include <fit/detail/result_of.h>
#include <fit/detail/move.h>
#include <fit/detail/make.h>
Expand Down Expand Up @@ -160,17 +160,17 @@ template<class Projection, class F=void>
struct by_adaptor;

template<class Projection, class F>
struct by_adaptor : Projection, F
struct by_adaptor : detail::callable_base<Projection>, detail::callable_base<F>
{
typedef by_adaptor fit_rewritable_tag;
template<class... Ts>
constexpr const F& base_function(Ts&&... xs) const
constexpr const detail::callable_base<F>& base_function(Ts&&... xs) const
{
return always_ref(*this)(xs...);
}

template<class... Ts>
constexpr const Projection& base_projection(Ts&&... xs) const
constexpr const detail::callable_base<Projection>& base_projection(Ts&&... xs) const
{
return always_ref(*this)(xs...);
}
Expand All @@ -182,51 +182,51 @@ struct by_adaptor : Projection, F
{
template<class... Ts>
struct of
: Failure::template of<decltype(std::declval<Projection>()(std::declval<Ts>()))...>
: Failure::template of<decltype(std::declval<detail::callable_base<Projection>>()(std::declval<Ts>()))...>
{};
};
};

struct failure
: failure_map<by_failure, F>
: failure_map<by_failure, detail::callable_base<F>>
{};

FIT_INHERIT_DEFAULT(by_adaptor, Projection, F)
FIT_INHERIT_DEFAULT(by_adaptor, detail::callable_base<Projection>, F)

template<class P, class G, FIT_ENABLE_IF_CONVERTIBLE(P, Projection), FIT_ENABLE_IF_CONVERTIBLE(G, F)>
template<class P, class G, FIT_ENABLE_IF_CONVERTIBLE(P, detail::callable_base<Projection>), FIT_ENABLE_IF_CONVERTIBLE(G, detail::callable_base<F>)>
constexpr by_adaptor(P&& p, G&& f)
: Projection(fit::forward<P>(p)), F(fit::forward<G>(f))
: detail::callable_base<Projection>(fit::forward<P>(p)), detail::callable_base<F>(fit::forward<G>(f))
{}

FIT_RETURNS_CLASS(by_adaptor);

template<class... Ts>
constexpr FIT_SFINAE_RESULT(const F&, result_of<const Projection&, id_<Ts>>...)
constexpr FIT_SFINAE_RESULT(const detail::callable_base<F>&, result_of<const detail::callable_base<Projection>&, id_<Ts>>...)
operator()(Ts&&... xs) const FIT_SFINAE_RETURNS
(
detail::by_eval(
FIT_MANGLE_CAST(const Projection&)(FIT_CONST_THIS->base_projection(xs...)),
FIT_MANGLE_CAST(const F&)(FIT_CONST_THIS->base_function(xs...)),
FIT_MANGLE_CAST(const detail::callable_base<Projection>&)(FIT_CONST_THIS->base_projection(xs...)),
FIT_MANGLE_CAST(const detail::callable_base<F>&)(FIT_CONST_THIS->base_function(xs...)),
fit::forward<Ts>(xs)...
)
);
};

template<class Projection>
struct by_adaptor<Projection, void> : Projection
struct by_adaptor<Projection, void> : detail::callable_base<Projection>
{
typedef by_adaptor fit_rewritable1_tag;
template<class... Ts>
constexpr const Projection& base_projection(Ts&&... xs) const
constexpr const detail::callable_base<Projection>& base_projection(Ts&&... xs) const
{
return always_ref(*this)(xs...);
}

FIT_INHERIT_DEFAULT(by_adaptor, Projection)
FIT_INHERIT_DEFAULT(by_adaptor, detail::callable_base<Projection>)

template<class P, FIT_ENABLE_IF_CONVERTIBLE(P, Projection)>
template<class P, FIT_ENABLE_IF_CONVERTIBLE(P, detail::callable_base<Projection>)>
constexpr by_adaptor(P&& p)
: Projection(fit::forward<P>(p))
: detail::callable_base<Projection>(fit::forward<P>(p))
{}

FIT_RETURNS_CLASS(by_adaptor);
Expand Down

0 comments on commit fa265bb

Please sign in to comment.