A Lexically Typed
Object is a named lvalue whose type is referable by using prefix
T_
.
For any Lexically
Typed Object a
the
following must be met:
a
is a named lvalue.
a
doesn't begin
with a single underscore, T_%%a
is
__typeof
(a)
;
TT%%a
otherwise.
typedef int T_a; T_a a; typedef int TT_1; TT_1 _1;
A Pipable Function
Object is a Function
Object which behaves as if it were a "pipe" using operator|
and operator|=
.
Tip | |
---|---|
According to Charles Brockman's research, "pipable" is not misspelling of "pipeable". |
In addition to the requirements defined in the refinements, for any Pipable Function Object
p
the following must be met:
x|p(x1,...,xN)
is a valid expresion if and only if p(x1,...,xN)|=x
is a valid expression.
x|p(x1,...,xN)
and p(x1,...,xN)|=x
have the same effects.
N
is 0
,
then x|p()
,
x|p
, p|=x
,
and p()|=x
are valid expressions which have the
same effects.
operator|
works with left-to-right associativity.
operator|=
works with right-to-left associativity.
struct pipable { pipable operator()() const { return *this; } }; int operator|(int ch, pipable) { return std::toupper(ch); } int operator|=(pipable, int ch) { return std::toupper(ch); } void test() { pipable const to_upper = {}; int maybeA = 'a'|to_upper(); BOOST_CHECK(maybeA == 'A'); int maybeB = to_upper|='b'; BOOST_CHECK(maybeB == 'B'); }
An Ambi Function Object is a Pipable Function Object which can be used also as free function.
Tip | |
---|---|
"ambi" is short of "ambidextrous". |
In addition to the requirements defined in the refinements, for any Ambi Function Object
i
the following must be met:
x|i(x1,...,xN)
is a valid expression if and only if
i(x, x1,...,xN)
is a valid expression.
x|i(x1,...,xN)
and i(x,
x1,...,xN)
have
the same effects.
Note | |
---|---|
A Pipable Function Object can be overloaded with different arities, whereas Ambi Function Object cannot. |
struct ambi { int operator()(int ch) const { return std::tolower(ch); } ambi operator()() const { return *this; } }; int operator|(int ch, ambi) { return std::tolower(ch); } int operator|=(ambi, int ch) { return std::tolower(ch); } void test() { ambi const to_lower = {}; int maybei = 'I'|to_lower; BOOST_CHECK(maybei == 'i'); int maybej = to_lower('J'); BOOST_CHECK(maybej == 'j'); }
A Major Function Object is a Polymorphic Function Object which can be used with Boost.Lambda. Egg is a library which helps you define your own Major Function Object.
In addition to the requirements defined in the refinements, for any Major Function Object
f
the following must be met:
f
can be used as the first
argument of boost::lambda::bind
.
Tip | |
---|---|
This concept can be implemented without depending on Boost.Lambda library. |
A Static Function Object is a Major Function Object which is intended to replace normal functions.
In addition to the requirements defined in the refinements, for any Static Function Object
f
the following must be met:
__typeof
(f)
is POD in C++03 (a trivial type
in C++0x).
__typeof
(f)
is Default
Constructible and Copy
Assignable.
f
is statically
initialized.
boost::remove_reference<__decltype
(f)>::type
is __typeof
(f) const
.
boost::result_of<__typeof
(f)
const(a1,...,aN)>::type
is a valid expression, boost::result_of<__typeof
(f)(a1,...,aN)>::type
is a valid expression which is the
same type.
Note | |
---|---|
A Static Function Object can be singular, meaning that it may result in undefined behavior to call a default constructed one. |
typedef int (*T_is_alpha)(int ch); T_is_alpha const is_alpha = &std::isalpha;
A Little Function type is a type which Function Builders require.
For any Little Function
type L
the following must
be met:
L
has a nested class template
named apply
, where apply<...>::type
means return type of function calls.
L
has a const member
function named call
whose return type is explicitly specified by the first template parameter.
struct little_identity { template<class Self, class T> struct apply { typedef T &type; }; template<class Auto, class T> Auto call(T &x) const { return x; } };
Caution | |
---|---|
Boost.ResultOf document in boost.org is outdated. |
Lvalues are indicated by passing a reference type, rvalues are indicated by passing a non-reference type:
#include <boost/utility/result_of.hpp> using boost::result_of; struct T_plus { typedef int result_type; result_type operator()(int i, int j) const { return i + j; } }; void test_lvalue() { int i = 2; result_of<T_plus(int &, int)>::type r = T_plus()(i, 3); BOOST_CHECK( r == 5 ); }
Thanks to this convention, you can easily write a "chain" of Boost.ResultOf:
void test_chain() { int const i = 3; result_of< T_plus(result_of<T_plus(int, int)>::type, int const &) >::type r = T_plus()(T_plus()(1, 2), i); BOOST_CHECK( r == 6 ); }
A callable type can't be a reference type
but must be "const-correct", meaning that you must add const
to const-qualified
Function Object
type:
T_plus const plus = {}; void test_const() { result_of<T_plus const(int, int)>::type r = plus(2, 3); BOOST_CHECK( r == 5 ); }
However, if a library guarantees the same behavior between const-qualified
type and non-const-qualified type (as Static
Function Object does so), you could omit const
:
void test_nonconst() { result_of<T_plus(int, int)>::type r = plus(2, 3); BOOST_CHECK( r == 5 ); }
These bugs can be worked around by egg::result_of_
in <boost/egg/result_of.hpp>
.
The first bug is fixed with Boost1.35.