...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
The entire contents of the header <boost/utility.hpp>
are in namespace boost
.
utility.hpp
The class template
result_of
helps determine the type of a
call expression. For example, given an lvalue f
of
type F
and lvalues t1
,
t2
, ..., tN
of
types T1
, T2
, ...,
TN
, respectively, the type
result_of<F(T1, T2, ...,
TN)>::type
defines the result type
of the expression f(t1, t2,
...,tN)
. This implementation permits
the type F
to be a function pointer,
function reference, member function pointer, or class
type. By default, N may be any value between 0 and
16. To change the upper limit, define the macro
BOOST_RESULT_OF_NUM_ARGS
to the maximum
value for N. Class template result_of
resides in the header <boost/utility/result_of.hpp>
.
If your compiler's support for decltype
is
adequate, result_of
automatically uses it to
deduce the type of the call expression, in which case
result_of<F(T1, T2, ...,
TN)>::type
names the type
decltype(boost::declval<F>()(boost::declval<T1>(),
boost::declval<T2>(), ...,
boost::declval<TN>()))
, as in the
following example.
struct functor { template<class T> T operator()(T x) { return x; } }; typedef boost::result_of< functor(int) >::type type; // type is int
You can test whether result_of
is using
decltype
by checking if the macro
BOOST_RESULT_OF_USE_DECLTYPE
is defined after
including result_of.hpp
. You can also force
result_of
to use decltype
by
defining BOOST_RESULT_OF_USE_DECLTYPE
prior
to including result_of.hpp
.
If decltype
is not used,
then automatic result type deduction of function
objects is not possible. Instead, result_of
uses the following protocol to allow the programmer to
specify a type. When F
is a class type with a
member type result_type
,
result_of<F(T1, T2, ...,
TN)>::type
is
F::result_type
. When F
does
not contain result_type
,
result_of<F(T1, T2, ...,
TN)>::type
is F::result<F(T1,
T2, ..., TN)>::type
when
N > 0
or void
when N = 0
. Note that it is the
responsibility of the programmer to ensure that
function objects accurately advertise their result
type via this protocol, as in the following
example.
struct functor { template<class> struct result; template<class F, class T> struct result<F(T)> { typedef T type; }; template<class T> T operator()(T x) { return x; } }; typedef boost::result_of< functor(int) >::type type; // type is int
Since decltype
is a new language
feature recently standardized in C++11,
if you are writing a function object
to be used with result_of
, for
maximum portability, you might consider following
the above protocol even if your compiler has
proper decltype
support. If you wish to continue to
use the protocol on compilers that
support decltype
, there are two options:
You can use boost::tr1_result_of
, which is also
defined in <boost/utility/result_of.hpp>
.
Alternatively, you can define the macro
BOOST_RESULT_OF_USE_TR1
, which causes
result_of
to use the protocol described
above instead of decltype
. If you choose to
follow the protocol, take care to ensure that the
result_type
and
result<>
members accurately
represent the return type of
operator()
given a call expression.
Additionally, boost::result_of
provides a third mode of operation, which some users
may find convenient. When
BOOST_RESULT_OF_USE_TR1_WITH_DECLTYPE_FALLBACK
is defined, boost::result_of
behaves as
follows. If the function object has a member
type result_type
or member
template result<>
, then
boost::result_of
will use the TR1
protocol. Otherwise,
boost::result_of
will
use decltype
. Using TR1 with
a declytpe
fallback may workaround
certain problems at the cost of portability. For
example:
boost::result_of
to work
with incomplete return types but your
compiler's decltype
implementation
does not support incomplete return types, then you
can use the TR1 protocol as a workaround. Support
for incomplete return types was added late in the
C++11 standardization process
(see N3276)
and is not implemented by some compilers.decltype
, then using TR1 with a
decltype
fallback will allow you to
work with both your existing TR1 function objects
and new C++11 function object. This situation
could occur if your legacy function objects
misused the TR1 protocol. See the documentation on
known differences
between boost::result_of
and TR1.This implementation of result_of
requires class template partial specialization, the
ability to parse function types properly, and support
for SFINAE. If result_of
is not supported
by your compiler, including the header
boost/utility/result_of.hpp
will
define the macro BOOST_NO_RESULT_OF
.
For additional information
about result_of
, see the C++ Library
Technical Report,
N1836,
or, for motivation and design rationale,
the result_of
proposal.
The following are general suggestions about when
and how to use boost::result_of
.
std::result_of
. If std::result_of
meets your needs, then there's no reason to stop using
it.boost::result_of
with
decltype
. When decltype
is
used boost::result_of
and std::result_of
are usually
interchangeable. See the documentation on
known differences
between boost::result_of and C++11 result_of.boost::result_of
with the TR1 protocol.Regardless of how you
configure boost::result_of
, it is
important to bear in mind that the return type of a
function may change depending on its arguments, and
additionally, the return type of a member function may
change depending on the cv-qualification of the
object. boost::result_of
must be passed
the appropriately cv-qualified types in order to
deduce the corresponding return type. For example:
struct functor { int& operator()(int); int const& operator()(int) const; float& operator()(float&); float const& operator()(float const&); }; typedef boost::result_of< functor(int) >::type type1; // type1 is int & typedef boost::result_of< const functor(int) >::type type2; // type2 is int const & typedef boost::result_of< functor(float&) >::type type3; // type3 is float & typedef boost::result_of< functor(float const&) >::type type4; // type4 is float const &
On compliant C++11
compilers, boost::result_of
can
use decltype
to deduce the type of any
call expression, including calls to function
objects. However, on pre-C++11 compilers or on
compilers without adequate decltype support,
additional scaffolding is needed from function
objects as described above. The following are
suggestions about how to use the TR1 protocol.
result_type
. There is no need
to use the result
template unless the
return type varies.struct functor { typedef int result_type; result_type operator()(int); };
result
specialization near the corresponding
operator()
overload. This can make it
easier to keep the specializations in sync with the
overloads. For example:
struct functor { template<class> struct result; template<class F> struct result<F(int)> { typedef int& type; }; result<functor(int)>::type operator()(int); template<class F> struct result<const F(int)> { typedef int const& type; }; result<const functor(int)>::type operator()(int) const; };
result
template specialization. For
example, the following uses
Boost.TypeTraits
to specialize the result
template for
a single operator()
that can be called on
both a const and non-const function object with
either an lvalue or rvalue argument.
struct functor { template<class> struct result; template<class F, class T> struct result<F(T)> : boost::remove_cv< typename boost::remove_reference<T>::type > {}; template<class T> T operator()(T const& x) const; };
decltype
, boost::result_of
ignores the TR1 protocol and instead deduces the
return type of function objects directly
via decltype
. In most situations, users
will not notice a difference, so long as they use the
protocol correctly. The following are situations in
which the type deduced
by boost::result_of
is known to differ depending on
whether decltype
or the TR1 protocol is
used.
When using the TR1
protocol, boost::result_of
cannot
detect whether the actual type of a call to a
function object is the same as the type specified
by the protocol, which allows for the possibility
of inadvertent mismatches between the specified
type and the actual type. When
using decltype
, these subtle bugs
may result in compilation errors. For example:
struct functor { typedef short result_type; int operator()(short); }; #ifdef BOOST_RESULT_OF_USE_DECLTYPE BOOST_STATIC_ASSERT(( boost::is_same<boost::result_of<functor(short)>::type, int>::value )); #else BOOST_STATIC_ASSERT(( boost::is_same<boost::result_of<functor(short)>::type, short>::value )); #endif
Note that the user can
force boost::result_of
to use the TR1
protocol even on platforms that
support decltype
by
defining BOOST_RESULT_OF_USE_TR1
.
When using the TR1 protocol, boost::result_of
cannot always deduce the type of calls to
nullary function objects, in which case the
type defaults to void. When using decltype
,
boost::result_of
always gives the actual type of the
call expression. For example:
struct functor { template<class> struct result { typedef int type; }; int operator()(); }; #ifdef BOOST_RESULT_OF_USE_DECLTYPE BOOST_STATIC_ASSERT(( boost::is_same<boost::result_of<functor()>::type, int>::value )); #else BOOST_STATIC_ASSERT(( boost::is_same<boost::result_of<functor()>::type, void>::value )); #endif
Note that there are some workarounds for the
nullary function problem. So long as the return
type does not vary,
result_type
can always be used to
specify the return type regardless of arity. If the
return type does vary, then the user can
specialize boost::result_of
itself for
nullary calls.
When using the TR1
protocol, boost::result_of
will
report the cv-qualified type specified
by result_type
or
the result
template regardless of
the actual cv-qualification of the call
expression. When using
decltype
, boost::result_of
will report the actual type of the call expression,
which is not cv-qualified when the expression is a
non-class prvalue. For example:
struct functor { template<class> struct result; template<class F, class T> struct result<F(const T)> { typedef const T type; }; const short operator()(const short); int const & operator()(int const &); }; // Non-prvalue call expressions work the same with or without decltype. BOOST_STATIC_ASSERT(( boost::is_same< boost::result_of<functor(int const &)>::type, int const & ::value )); // Non-class prvalue call expressions are not actually cv-qualified, // but only the decltype-based result_of reports this accurately. #ifdef BOOST_RESULT_OF_USE_DECLTYPE BOOST_STATIC_ASSERT(( boost::is_same< boost::result_of<functor(const short)>::type, short ::value )); #else BOOST_STATIC_ASSERT(( boost::is_same< boost::result_of<functor(const short)>::type, const short ::value )); #endif
When using decltype
, boost::result_of
implements most of the C++11 result_of
specification. One known exception is that
boost::result_of
does not implement the
requirements regarding pointers to member data.
Created by Doug Gregor. Contributions from Daniel Walker, Eric Niebler, Michel Morin and others
The macro BOOST_BINARY
is used for the
representation of binary literals. It takes as an argument
a binary number arranged as an arbitrary amount of 1s and 0s in
groupings of length 1 to 8, with groups separated
by spaces. The type of the literal yielded is determined by
the same rules as those of hex and octal
literals (2.13.1p1). By implementation, this macro
expands directly to an octal literal during preprocessing, so
there is no overhead at runtime and the result is useable in
any place that an octal literal would be.
In order to directly support binary literals with suffixes, additional macros of the form BOOST_BINARY_XXX are also provided, where XXX is a standard integer suffix in all capital letters. In addition, LL and ULL suffixes may be used for representing long long and unsigned long long types in compilers which provide them as an extension.
The BOOST_BINARY family of macros resides in the header <boost/utility/binary.hpp> which is automatically included by <boost/utility.hpp>.
Contributed by Matt Calabrese.
void foo( int ); void foo( unsigned long ); void bar() { int value1 = BOOST_BINARY( 100 111000 01 1 110 ); unsigned long value2 = BOOST_BINARY_UL( 100 001 ); // unsigned long long long value3 = BOOST_BINARY_LL( 11 000 ); // long long if supported assert( BOOST_BINARY( 10010 ) & BOOST_BINARY( 11000 ) == BOOST_BINARY( 10000 ) ); foo( BOOST_BINARY( 1010 ) ); // calls the first foo foo( BOOST_BINARY_LU( 1010 ) ); // calls the second foo }
Revised 04 September, 2008
© Copyright Beman Dawes 1999-2003.
Distributed under the Boost Software License, Version 1.0. See www.boost.org/LICENSE_1_0.txt