forked from boostorg/core
More documentation for core
This commit is contained in:
@@ -37,7 +37,7 @@ namespace boost
|
|||||||
|
|
||||||
[section checked_delete]
|
[section checked_delete]
|
||||||
|
|
||||||
[section `template<class T> void checked_delete(T * p);`]
|
[section template<class T> void checked_delete(T * p);]
|
||||||
|
|
||||||
* *Requires:* *T* must be a complete type. The expression
|
* *Requires:* *T* must be a complete type. The expression
|
||||||
`delete p` must be well-formed.
|
`delete p` must be well-formed.
|
||||||
@@ -49,7 +49,7 @@ namespace boost
|
|||||||
|
|
||||||
[section checked_array_delete]
|
[section checked_array_delete]
|
||||||
|
|
||||||
[section `template<class T> void checked_array_delete(T * p);`]
|
[section template<class T> void checked_array_delete(T * p);]
|
||||||
|
|
||||||
* *Requires:* *T* must be a complete type. The expression
|
* *Requires:* *T* must be a complete type. The expression
|
||||||
`delete [] p` must be well-formed.
|
`delete [] p` must be well-formed.
|
||||||
@@ -70,7 +70,7 @@ template<class T> struct checked_deleter
|
|||||||
};
|
};
|
||||||
``
|
``
|
||||||
|
|
||||||
[section `void checked_deleter<T>::operator()(T * p) const;`]
|
[section void checked_deleter<T>::operator()(T * p) const;]
|
||||||
|
|
||||||
* *Requires:* `T` must be a complete type. The expression
|
* *Requires:* `T` must be a complete type. The expression
|
||||||
`delete p` must be well-formed.
|
`delete p` must be well-formed.
|
||||||
@@ -91,10 +91,11 @@ template<class T> struct checked_array_deleter
|
|||||||
};
|
};
|
||||||
``
|
``
|
||||||
|
|
||||||
[section `void checked_array_deleter<T>::operator()(T * p) const;`]
|
[section void checked_array_deleter<T>::operator()(T * p) const;]
|
||||||
|
|
||||||
* *Requires:* `T` must be a complete type. The expression
|
* *Requires:* `T` must be a complete type. The expression
|
||||||
`delete [] p` must be well-formed.
|
`delete [] p` must be well-formed.
|
||||||
* `Effects:` `delete [] p;`
|
* *Effects:* `delete [] p;`
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
|
25
doc/core.qbk
25
doc/core.qbk
@@ -34,9 +34,15 @@ Currently, the Core library contains:
|
|||||||
[`boost::checked_delete`]
|
[`boost::checked_delete`]
|
||||||
]
|
]
|
||||||
[
|
[
|
||||||
[[@../../enable_if.html enable_if]]
|
[[link core.enable_if enable_if]]
|
||||||
[`boost::enable_if`]
|
[`boost::enable_if`]
|
||||||
]
|
]
|
||||||
|
[
|
||||||
|
[[link core.explicit_operator_bool explicit_operator_bool]]
|
||||||
|
[`BOOST_EXPLICIT_OPERATOR_BOOL,
|
||||||
|
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT,
|
||||||
|
BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL`]
|
||||||
|
]
|
||||||
[
|
[
|
||||||
[[link core.ignore_unused ignore_unused]]
|
[[link core.ignore_unused ignore_unused]]
|
||||||
[`boost::ignore_unused`]
|
[`boost::ignore_unused`]
|
||||||
@@ -54,6 +60,10 @@ Currently, the Core library contains:
|
|||||||
[[link core.noncopyable noncopyable]]
|
[[link core.noncopyable noncopyable]]
|
||||||
[`boost::noncopyable`]
|
[`boost::noncopyable`]
|
||||||
]
|
]
|
||||||
|
[
|
||||||
|
[[link core.null_deleter null_deleter]]
|
||||||
|
[`boost::null_deleter`]
|
||||||
|
]
|
||||||
[
|
[
|
||||||
[ref]
|
[ref]
|
||||||
[`boost::ref`]
|
[`boost::ref`]
|
||||||
@@ -62,26 +72,17 @@ Currently, the Core library contains:
|
|||||||
[[link core.swap swap]]
|
[[link core.swap swap]]
|
||||||
[`boost::swap`]
|
[`boost::swap`]
|
||||||
]
|
]
|
||||||
[
|
|
||||||
[[link core.null_deleter null_deleter]]
|
|
||||||
[`boost::null_deleter`]
|
|
||||||
]
|
|
||||||
[
|
|
||||||
[[link core.explicit_operator_bool explicit_operator_bool]]
|
|
||||||
[`BOOST_EXPLICIT_OPERATOR_BOOL,
|
|
||||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT,
|
|
||||||
BOOST_CONSTEXPR_EXPLICIT_OPERATOR_BOOL`]
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
|
||||||
[include:core addressof.qbk]
|
[include:core addressof.qbk]
|
||||||
[include:core checked_delete.qbk]
|
[include:core checked_delete.qbk]
|
||||||
|
[include:core enable_if.qbk]
|
||||||
[include:core explicit_operator_bool.qbk]
|
[include:core explicit_operator_bool.qbk]
|
||||||
[include:core ignore_unused.qbk]
|
[include:core ignore_unused.qbk]
|
||||||
[include:core lightweight_test.qbk]
|
[include:core lightweight_test.qbk]
|
||||||
[include:core no_exceptions_support.qbk]
|
[include:core no_exceptions_support.qbk]
|
||||||
[include:core noncopyable.qbk]
|
[include:core noncopyable.qbk]
|
||||||
[include:core swap.qbk]
|
|
||||||
[include:core null_deleter.qbk]
|
[include:core null_deleter.qbk]
|
||||||
|
[include:core swap.qbk]
|
||||||
|
461
doc/enable_if.qbk
Normal file
461
doc/enable_if.qbk
Normal file
@@ -0,0 +1,461 @@
|
|||||||
|
[section:enable_if Header <boost/core/enable_if.hpp>]
|
||||||
|
|
||||||
|
[section Introduction]
|
||||||
|
|
||||||
|
The `enable_if` family of templates is a set of tools to allow
|
||||||
|
a function template or a class template specialization to
|
||||||
|
include or exclude itself from a set of matching functions or
|
||||||
|
specializations based on properties of its template arguments.
|
||||||
|
For example, one can define function templates that are only
|
||||||
|
enabled for, and thus only match, an arbitrary set of types
|
||||||
|
defined by a traits class. The `enable_if` templates can also
|
||||||
|
be applied to enable class template specializations.
|
||||||
|
Applications of `enable_if` are discussed in length in
|
||||||
|
[link REF1 \[1\]] and [link REF2 \[2\]].
|
||||||
|
|
||||||
|
[section Synopsis]
|
||||||
|
|
||||||
|
``
|
||||||
|
namespace boost {
|
||||||
|
template <class Cond, class T = void> struct enable_if;
|
||||||
|
template <class Cond, class T = void> struct disable_if;
|
||||||
|
template <class Cond, class T> struct lazy_enable_if;
|
||||||
|
template <class Cond, class T> struct lazy_disable_if;
|
||||||
|
|
||||||
|
template <bool B, class T = void> struct enable_if_c;
|
||||||
|
template <bool B, class T = void> struct disable_if_c;
|
||||||
|
template <bool B, class T> struct lazy_enable_if_c;
|
||||||
|
template <bool B, class T> struct lazy_disable_if_c;
|
||||||
|
}
|
||||||
|
``
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section Background]
|
||||||
|
|
||||||
|
Sensible operation of template function overloading in C++
|
||||||
|
relies on the /SFINAE/ (substitution-failure-is-not-an-error)
|
||||||
|
principle [link REF3 \[3\]]: if an invalid argument or return
|
||||||
|
type is formed during the instantiation of a function template,
|
||||||
|
the instantiation is removed from the overload resolution set
|
||||||
|
instead of causing a compilation error. The following example,
|
||||||
|
taken from [link REF1 \[1\]], demonstrates why this is
|
||||||
|
important:
|
||||||
|
|
||||||
|
``
|
||||||
|
int negate(int i) { return -i; }
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
typename F::result_type negate(const F& f) { return -f(); }
|
||||||
|
``
|
||||||
|
|
||||||
|
Suppose the compiler encounters the call `negate(1)`. The first
|
||||||
|
definition is obviously a better match, but the compiler must
|
||||||
|
nevertheless consider (and instantiate the prototypes) of both
|
||||||
|
definitions to find this out. Instantiating the latter
|
||||||
|
definition with `F` as `int` would result in:
|
||||||
|
|
||||||
|
``
|
||||||
|
int::result_type negate(const int&);
|
||||||
|
``
|
||||||
|
|
||||||
|
where the return type is invalid. If this were an error, adding
|
||||||
|
an unrelated function template (that was never called) could
|
||||||
|
break otherwise valid code. Due to the SFINAE principle the
|
||||||
|
above example is not, however, erroneous. The latter definition
|
||||||
|
of `negate` is simply removed from the overload resolution set.
|
||||||
|
|
||||||
|
The `enable_if` templates are tools for controlled creation of
|
||||||
|
the SFINAE conditions.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section The enable_if templates]
|
||||||
|
|
||||||
|
The names of the `enable_if` templates have three parts: an
|
||||||
|
optional `lazy_` tag, either `enable_if` or `disable_if`, and
|
||||||
|
an optional `_c` tag. All eight combinations of these parts
|
||||||
|
are supported. The meaning of the `lazy_` tag is described
|
||||||
|
in the section [link
|
||||||
|
core.enable_if.using_enable_if.enable_if_lazy below]. The
|
||||||
|
second part of the name indicates whether a true condition
|
||||||
|
argument should enable or disable the current overload. The
|
||||||
|
third part of the name indicates whether the condition
|
||||||
|
argument is a `bool` value (`_c` suffix), or a type containing
|
||||||
|
a static `bool` constant named `value` (no suffix). The latter
|
||||||
|
version interoperates with Boost.MPL.
|
||||||
|
|
||||||
|
The definitions of `enable_if_c` and `enable_if` are as follows
|
||||||
|
(we use `enable_if` templates unqualified but they are in the
|
||||||
|
`boost` namespace).
|
||||||
|
|
||||||
|
``
|
||||||
|
template <bool B, class T = void>
|
||||||
|
struct enable_if_c {
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct enable_if_c<false, T> {};
|
||||||
|
|
||||||
|
template <class Cond, class T = void>
|
||||||
|
struct enable_if : public enable_if_c<Cond::value, T> {};
|
||||||
|
``
|
||||||
|
|
||||||
|
An instantiation of the `enable_if_c` template with the
|
||||||
|
parameter `B` as `true` contains a member type `type`, defined
|
||||||
|
to be `T`. If `B` is `false`, no such member is defined. Thus
|
||||||
|
`enable_if_c<B, T>::type` is either a valid or an invalid type
|
||||||
|
expression, depending on the value of `B`. When valid,
|
||||||
|
`enable_if_c<B, T>::type` equals `T`. The `enable_if_c`
|
||||||
|
template can thus be used for controlling when functions are
|
||||||
|
considered for overload resolution and when they are not. For
|
||||||
|
example, the following function is defined for all arithmetic
|
||||||
|
types (according to the classification of the Boost
|
||||||
|
*type_traits* library):
|
||||||
|
|
||||||
|
``
|
||||||
|
template <class T>
|
||||||
|
typename enable_if_c<boost::is_arithmetic<T>::value, T>::type
|
||||||
|
foo(T t) { return t; }
|
||||||
|
``
|
||||||
|
|
||||||
|
The `disable_if_c` template is provided as well, and has the
|
||||||
|
same functionality as `enable_if_c` except for the negated
|
||||||
|
condition. The following function is enabled for all
|
||||||
|
non-arithmetic types.
|
||||||
|
|
||||||
|
``
|
||||||
|
template <class T>
|
||||||
|
typename disable_if_c<boost::is_arithmetic<T>::value, T>::type
|
||||||
|
bar(T t) { return t; }
|
||||||
|
``
|
||||||
|
|
||||||
|
For easier syntax in some cases and interoperation with
|
||||||
|
Boost.MPL we provide versions of the `enable_if` templates
|
||||||
|
taking any type with a `bool` member constant named `value` as
|
||||||
|
the condition argument. The MPL `bool_`, `and_`, `or_`, and
|
||||||
|
`not_` templates are likely to be useful for creating such
|
||||||
|
types. Also, the traits classes in the Boost.Type_traits
|
||||||
|
library follow this convention. For example, the above example
|
||||||
|
function `foo` can be alternatively written as:
|
||||||
|
|
||||||
|
``
|
||||||
|
template <class T>
|
||||||
|
typename enable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t) { return t; }
|
||||||
|
``
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:using_enable_if Using enable_if]
|
||||||
|
|
||||||
|
The `enable_if` templates are defined in
|
||||||
|
`boost/utility/enable_if.hpp`, which is included by
|
||||||
|
`boost/utility.hpp`.
|
||||||
|
|
||||||
|
With respect to function templates, `enable_if` can be used in
|
||||||
|
multiple different ways:
|
||||||
|
|
||||||
|
* As the return type of an instantiatied function
|
||||||
|
* As an extra parameter of an instantiated function
|
||||||
|
* As an extra template parameter (useful only in a compiler
|
||||||
|
that supports C++0x default arguments for function template
|
||||||
|
parameters, see [link
|
||||||
|
core.enable_if.using_enable_if.enable_if_0x Enabling function
|
||||||
|
templates in C++0x] for details.
|
||||||
|
|
||||||
|
In the previous section, the return type form of `enable_if`
|
||||||
|
was shown. As an example of using the form of `enable_if` that
|
||||||
|
works via an extra function parameter, the `foo` function in
|
||||||
|
the previous section could also be written as:
|
||||||
|
|
||||||
|
``
|
||||||
|
template <class T>
|
||||||
|
T foo(T t,
|
||||||
|
typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0);
|
||||||
|
``
|
||||||
|
|
||||||
|
Hence, an extra parameter of type `void*` is added, but it is
|
||||||
|
given a default value to keep the parameter hidden from client
|
||||||
|
code. Note that the second template argument was not given to
|
||||||
|
`enable_if`, as the default `void` gives the desired behavior.
|
||||||
|
|
||||||
|
Which way to write the enabler is largely a matter of taste,
|
||||||
|
but for certain functions, only a subset of the options is
|
||||||
|
possible:
|
||||||
|
|
||||||
|
* Many operators have a fixed number of arguments, thus
|
||||||
|
`enable_if` must be used either in the return type or in an
|
||||||
|
extra template parameter.
|
||||||
|
* Functions that have a variadic parameter list must use either
|
||||||
|
the return type form or an extra template parameter.
|
||||||
|
* Constructors do not have a return type so you must use either
|
||||||
|
an extra function parameter or an extra template parameter.
|
||||||
|
* Constructors that have a variadic parameter list must an
|
||||||
|
extra template parameter.
|
||||||
|
* Conversion operators can only be written with an extra
|
||||||
|
template parameter.
|
||||||
|
|
||||||
|
[section:enable_if_0x Enabling function templates in C++0x]
|
||||||
|
|
||||||
|
In a compiler which supports C++0x default arguments for
|
||||||
|
function template parameters, you can enable and disable
|
||||||
|
function templates by adding an additional template parameter.
|
||||||
|
This approach works in all situations where you would use
|
||||||
|
either the return type form of `enable_if` or the function
|
||||||
|
parameter form, including operators, constructors, variadic
|
||||||
|
function templates, and even overloaded conversion operations.
|
||||||
|
|
||||||
|
As an example:
|
||||||
|
|
||||||
|
``
|
||||||
|
#include <boost/type_traits/is_arithmetic.hpp>
|
||||||
|
#include <boost/type_traits/is_pointer.hpp>
|
||||||
|
#include <boost/utility/enable_if.hpp>
|
||||||
|
|
||||||
|
class test
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// A constructor that works for any argument list of size 10
|
||||||
|
template< class... T,
|
||||||
|
typename boost::enable_if_c< sizeof...( T ) == 10,
|
||||||
|
int >::type = 0>
|
||||||
|
test( T&&... );
|
||||||
|
|
||||||
|
// A conversion operation that can convert to any arithmetic type
|
||||||
|
template< class T,
|
||||||
|
typename boost::enable_if< boost::is_arithmetic< T >,
|
||||||
|
int >::type = 0>
|
||||||
|
operator T() const;
|
||||||
|
|
||||||
|
// A conversion operation that can convert to any pointer type
|
||||||
|
template< class T,
|
||||||
|
typename boost::enable_if< boost::is_pointer< T >,
|
||||||
|
int >::type = 0>
|
||||||
|
operator T() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
// Works
|
||||||
|
test test_( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 );
|
||||||
|
|
||||||
|
// Fails as expected
|
||||||
|
test fail_construction( 1, 2, 3, 4, 5 );
|
||||||
|
|
||||||
|
// Works by calling the conversion operator enabled for arithmetic types
|
||||||
|
int arithmetic_object = test_;
|
||||||
|
|
||||||
|
// Works by calling the conversion operator enabled for pointer types
|
||||||
|
int* pointer_object = test_;
|
||||||
|
|
||||||
|
// Fails as expected
|
||||||
|
struct {} fail_conversion = test_;
|
||||||
|
}
|
||||||
|
``
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section Enabling template class specializations]
|
||||||
|
|
||||||
|
Class template specializations can be enabled or disabled with
|
||||||
|
`enable_if`. One extra template parameter needs to be added for
|
||||||
|
the enabler expressions. This parameter has the default value
|
||||||
|
`void`. For example:
|
||||||
|
|
||||||
|
``
|
||||||
|
template <class T, class Enable = void>
|
||||||
|
class A { ... };
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class A<T, typename enable_if<is_integral<T> >::type> { ... };
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class A<T, typename enable_if<is_float<T> >::type> { ... };
|
||||||
|
``
|
||||||
|
|
||||||
|
Instantiating `A` with any integral type matches the first
|
||||||
|
specialization, whereas any floating point type matches the
|
||||||
|
second one. All other types match the primary template.
|
||||||
|
The condition can be any compile-time boolean expression that
|
||||||
|
depends on the template arguments of the class. Note that
|
||||||
|
again, the second argument to `enable_if` is not needed; the
|
||||||
|
default (`void`) is the correct value.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section Overlapping enabler conditions]
|
||||||
|
|
||||||
|
Once the compiler has examined the enabling conditions and
|
||||||
|
included the function into the overload resolution set, normal
|
||||||
|
C++ overload resolution rules are used to select the best
|
||||||
|
matching function. In particular, there is no ordering between
|
||||||
|
enabling conditions. Function templates with enabling
|
||||||
|
conditions that are not mutually exclusive can lead to
|
||||||
|
ambiguities. For example:
|
||||||
|
|
||||||
|
``
|
||||||
|
template <class T>
|
||||||
|
typename enable_if<boost::is_integral<T>, void>::type
|
||||||
|
foo(T t) {}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename enable_if<boost::is_arithmetic<T>, void>::type
|
||||||
|
foo(T t) {}
|
||||||
|
``
|
||||||
|
|
||||||
|
All integral types are also arithmetic. Therefore, say, for the
|
||||||
|
call `foo(1)`, both conditions are true and both functions are
|
||||||
|
thus in the overload resolution set. They are both equally good
|
||||||
|
matches and thus ambiguous. Of course, more than one enabling
|
||||||
|
condition can be simultaneously true as long as other arguments
|
||||||
|
disambiguate the functions.
|
||||||
|
|
||||||
|
The above discussion applies to using `enable_if` in class
|
||||||
|
template partial specializations as well.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:enable_if_lazy Lazy enable_if]
|
||||||
|
|
||||||
|
In some cases it is necessary to avoid instantiating part of a
|
||||||
|
function signature unless an enabling condition is true. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
``
|
||||||
|
template <class T, class U> class mult_traits;
|
||||||
|
|
||||||
|
template <class T, class U>
|
||||||
|
typename enable_if<is_multipliable<T, U>,
|
||||||
|
typename mult_traits<T, U>::type>::type
|
||||||
|
operator*(const T& t, const U& u) { ... }
|
||||||
|
``
|
||||||
|
|
||||||
|
Assume the class template `mult_traits` is a traits class
|
||||||
|
defining the resulting type of a multiplication operator. The
|
||||||
|
`is_multipliable` traits class specifies for which types to
|
||||||
|
enable the operator. Whenever `is_multipliable<A, B>::value` is
|
||||||
|
`true` for some types `A` and `B`, then
|
||||||
|
`mult_traits<A, B>::type` is defined.
|
||||||
|
|
||||||
|
Now, trying to invoke (some other overload) of `operator*`
|
||||||
|
with, say, operand types `C` and `D` for which
|
||||||
|
`is_multipliable<C, D>::value` is `false` and
|
||||||
|
`mult_traits<C, D>::type` is not defined is an error on some
|
||||||
|
compilers. The SFINAE principle is not applied because the
|
||||||
|
invalid type occurs as an argument to another template. The
|
||||||
|
`lazy_enable_if` and `lazy_disable_if` templates (and their
|
||||||
|
`_c` versions) can be used in such situations:
|
||||||
|
|
||||||
|
``
|
||||||
|
template<class T, class U>
|
||||||
|
typename lazy_enable_if<is_multipliable<T, U>,
|
||||||
|
mult_traits<T, U> >::type
|
||||||
|
operator*(const T& t, const U& u) { ... }
|
||||||
|
|
||||||
|
``The second argument of `lazy_enable_if` must be a class type
|
||||||
|
that defines a nested type named `type` whenever the first
|
||||||
|
parameter (the condition) is true.
|
||||||
|
|
||||||
|
[note Referring to one member type or static constant in a
|
||||||
|
traits class causes all of the members (type and static
|
||||||
|
constant) of that specialization to be instantiated.
|
||||||
|
Therefore, if your traits classes can sometimes contain invalid
|
||||||
|
types, you should use two distinct templates for describing the
|
||||||
|
conditions and the type mappings. In the above example,
|
||||||
|
`is_multipliable<T, U>::value` defines when
|
||||||
|
`mult_traits<T, U>::type` is valid.]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section Compiler workarounds]
|
||||||
|
|
||||||
|
Some compilers flag functions as ambiguous if the only
|
||||||
|
distinguishing factor is a different condition in an enabler
|
||||||
|
(even though the functions could never be ambiguous). For
|
||||||
|
example, some compilers (e.g. GCC 3.2) diagnose the following
|
||||||
|
two functions as ambiguous:
|
||||||
|
|
||||||
|
``
|
||||||
|
template <class T>
|
||||||
|
typename enable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename disable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t);
|
||||||
|
``
|
||||||
|
|
||||||
|
Two workarounds can be applied:
|
||||||
|
|
||||||
|
* Use an extra dummy parameter which disambiguates the
|
||||||
|
functions. Use a default value for it to hide the parameter
|
||||||
|
from the caller. For example:
|
||||||
|
``
|
||||||
|
template <int> struct dummy { dummy(int) {} };
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename enable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t, dummy<0> = 0);
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
typename disable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t, dummy<1> = 0);
|
||||||
|
``
|
||||||
|
* Define the functions in different namespaces and bring them
|
||||||
|
into a common namespace with `using` declarations:
|
||||||
|
``
|
||||||
|
namespace A {
|
||||||
|
template <class T>
|
||||||
|
typename enable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace B {
|
||||||
|
template <class T>
|
||||||
|
typename disable_if<boost::is_arithmetic<T>, T>::type
|
||||||
|
foo(T t);
|
||||||
|
}
|
||||||
|
|
||||||
|
using A::foo;
|
||||||
|
using B::foo;
|
||||||
|
``
|
||||||
|
Note that the second workaround above cannot be used for
|
||||||
|
member templates. On the other hand, operators do not accept
|
||||||
|
extra arguments, which makes the first workaround unusable.
|
||||||
|
As the net effect, neither of the workarounds are of
|
||||||
|
assistance for templated operators that need to be defined as
|
||||||
|
member functions (assignment and subscript operators).
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section Acknowledgements]
|
||||||
|
|
||||||
|
We are grateful to Howard Hinnant, Jason Shirk, Paul
|
||||||
|
Mensonides, and Richard Smith whose findings have
|
||||||
|
influenced the library.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section References]
|
||||||
|
|
||||||
|
* [#REF1] \[1\] Jaakko J\u00E4rvi, Jeremiah Willcock, Howard
|
||||||
|
Hinnant, and Andrew Lumsdaine. Function overloading based on
|
||||||
|
arbitrary properties of types. /C++ Users Journal/,
|
||||||
|
21(6):25--32, June 2003.
|
||||||
|
* [#REF2] \[2\] Jaakko J\u00E4rvi, Jeremiah Willcock, and
|
||||||
|
Andrew Lumsdaine. Concept-controlled polymorphism. In Frank
|
||||||
|
Pfennig and Yannis Smaragdakis, editors, /Generative
|
||||||
|
Programming and Component Engineering/, volume 2830 of
|
||||||
|
/LNCS/, pages 228--244. Springer Verlag, September 2003.
|
||||||
|
* [#REF3] \[3\] David Vandevoorde and Nicolai M. Josuttis.
|
||||||
|
/C++ Templates: The Complete Guide/. Addison-Wesley, 2002.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[endsect]
|
@@ -1,33 +1,55 @@
|
|||||||
[section:lightweight_test Header <boost/core/lightweight_test.hpp>]
|
[section:lightweight_test Header <boost/core/lightweight_test.hpp>]
|
||||||
|
|
||||||
If expression is false increases the error count and outputs a
|
[section BOOST_TEST]
|
||||||
message containing `expression`.
|
|
||||||
|
|
||||||
``
|
``
|
||||||
BOOST_TEST(expression)
|
BOOST_TEST(expression)
|
||||||
``
|
``
|
||||||
|
|
||||||
Increases error count and outputs a message containing
|
If expression is false increases the error count and outputs a
|
||||||
`message`.
|
message containing `expression`.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section BOOST_ERROR]
|
||||||
|
|
||||||
``
|
``
|
||||||
BOOST_ERROR(message)
|
BOOST_ERROR(message)
|
||||||
``
|
``
|
||||||
|
|
||||||
If `expr1` != `expr2` increases the error count and outputs a
|
Increases error count and outputs a message containing
|
||||||
message containing both expressions.
|
`message`.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section BOOST_TEST_EQ]
|
||||||
|
|
||||||
``
|
``
|
||||||
BOOST_TEST_EQ(expr1, expr2)
|
BOOST_TEST_EQ(expr1, expr2)
|
||||||
``
|
``
|
||||||
|
|
||||||
If `expr1` == `expr2` increases the error count and outputs a
|
If `expr1` != `expr2` increases the error count and outputs a
|
||||||
message containing both expressions.
|
message containing both expressions.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section BOOST_TEST_NE]
|
||||||
|
|
||||||
``
|
``
|
||||||
BOOST_TEST_NE(expr1, expr2)
|
BOOST_TEST_NE(expr1, expr2)
|
||||||
``
|
``
|
||||||
|
|
||||||
|
If `expr1` == `expr2` increases the error count and outputs a
|
||||||
|
message containing both expressions.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section BOOST_TEST_THROWS]
|
||||||
|
|
||||||
|
``
|
||||||
|
BOOST_TEST_THROWS(expr, excep)
|
||||||
|
``
|
||||||
|
|
||||||
If BOOST_NO_EXCEPTIONS is NOT defined and if `expr` does not
|
If BOOST_NO_EXCEPTIONS is NOT defined and if `expr` does not
|
||||||
throw an exception of type `excep`, increases the error count
|
throw an exception of type `excep`, increases the error count
|
||||||
and outputs a message containing the expression.
|
and outputs a message containing the expression.
|
||||||
@@ -35,14 +57,32 @@ and outputs a message containing the expression.
|
|||||||
If BOOST_NO_EXCEPTIONS is defined, this macro expands to
|
If BOOST_NO_EXCEPTIONS is defined, this macro expands to
|
||||||
nothing and `expr` is not evaluated.
|
nothing and `expr` is not evaluated.
|
||||||
|
|
||||||
``
|
[endsect]
|
||||||
BOOST_TEST_THROWS(expr, excep)
|
|
||||||
``
|
|
||||||
|
|
||||||
Returns the error count.
|
[section report_errors]
|
||||||
|
|
||||||
``
|
``
|
||||||
int boost::report_errors()
|
int boost::report_errors()
|
||||||
``
|
``
|
||||||
|
|
||||||
|
Return the error count from `main`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
``
|
||||||
|
#include <boost/core/lightweight_test.hpp>
|
||||||
|
|
||||||
|
void sqr( int x ); // should return x * x
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
BOOST_TEST( sqr( 2 ) == 4 );
|
||||||
|
BOOST_TEST_EQ( sqr(-3), 9 );
|
||||||
|
|
||||||
|
return boost::report_errors();
|
||||||
|
}
|
||||||
|
``
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
464
enable_if.html
464
enable_if.html
@@ -1,464 +0,0 @@
|
|||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
|
||||||
<HTML>
|
|
||||||
<HEAD><TITLE>enable_if</TITLE>
|
|
||||||
|
|
||||||
<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
||||||
<META name="GENERATOR" content="Microsoft FrontPage 5.0">
|
|
||||||
</HEAD>
|
|
||||||
<BODY >
|
|
||||||
<!--HEVEA command line is: hevea -nosymb -noiso -pedantic -v enable_if_docs_for_boost.tex -->
|
|
||||||
<!--HTMLHEAD-->
|
|
||||||
<!--ENDHTML-->
|
|
||||||
<!--PREFIX <ARG ></ARG>-->
|
|
||||||
<!--CUT DEF section 1 -->
|
|
||||||
<BR>
|
|
||||||
<BR>
|
|
||||||
|
|
||||||
|
|
||||||
<h1>
|
|
||||||
<img border="0" src="../../boost.png" align="center" width="277" height="86">enable_if</h1>
|
|
||||||
<BR>
|
|
||||||
<BR>
|
|
||||||
Copyright 2003 Jaakko Järvi, Jeremiah Willcock, Andrew Lumsdaine.<BR>
|
|
||||||
Copyright 2011 Matt Calabrese.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC section Introduction-->
|
|
||||||
|
|
||||||
<H2><A NAME="htoc1">1</A> Introduction</H2><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="introduction"></A>
|
|
||||||
The <TT>enable_if</TT> family of templates is a set of tools to allow a function template or a class template specialization
|
|
||||||
to include or exclude itself from a set of matching functions or specializations
|
|
||||||
based on properties of its template arguments.
|
|
||||||
For example, one can define function templates that
|
|
||||||
are only enabled for, and thus only match, an arbitrary set of types
|
|
||||||
defined by a traits class. The <TT>enable_if</TT> templates can also be
|
|
||||||
applied to enable class template specializations. Applications of
|
|
||||||
<TT>enable_if</TT> are discussed in length
|
|
||||||
in [<A HREF="#jarvi:03:cuj_arbitrary_overloading"><CITE>1</CITE></A>] and [<A HREF="#jarvi:03:c++typeclasses"><CITE>2</CITE></A>].<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC subsection Synopsis-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc2">1.1</A> Synopsis</H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:synopsis"></A>
|
|
||||||
<PRE>namespace boost {
|
|
||||||
template <class Cond, class T = void> struct enable_if;
|
|
||||||
template <class Cond, class T = void> struct disable_if;
|
|
||||||
template <class Cond, class T> struct lazy_enable_if;
|
|
||||||
template <class Cond, class T> struct lazy_disable_if;
|
|
||||||
|
|
||||||
template <bool B, class T = void> struct enable_if_c;
|
|
||||||
template <bool B, class T = void> struct disable_if_c;
|
|
||||||
template <bool B, class T> struct lazy_enable_if_c;
|
|
||||||
template <bool B, class T> struct lazy_disable_if_c;
|
|
||||||
}
|
|
||||||
</PRE>
|
|
||||||
<!--TOC subsection Background-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc3">1.2</A> Background</H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:background"></A>
|
|
||||||
Sensible operation of template function overloading in C++ relies
|
|
||||||
on the <EM>SFINAE</EM> (substitution-failure-is-not-an-error)
|
|
||||||
principle [<A HREF="#vandevoorde2002:templates"><CITE>3</CITE></A>]: if an invalid argument
|
|
||||||
or return type is formed during the instantiation of a function
|
|
||||||
template, the instantiation is removed from the overload resolution
|
|
||||||
set instead of causing a compilation error. The following example,
|
|
||||||
taken from [<A HREF="#jarvi:03:cuj_arbitrary_overloading"><CITE>1</CITE></A>],
|
|
||||||
demonstrates why this is important:
|
|
||||||
<PRE>int negate(int i) { return -i; }
|
|
||||||
|
|
||||||
template <class F>
|
|
||||||
typename F::result_type negate(const F& f) { return -f(); }
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
Suppose the compiler encounters the call <TT>negate(1)</TT>. The first
|
|
||||||
definition is obviously a better match, but the compiler must
|
|
||||||
nevertheless consider (and instantiate the prototypes) of both
|
|
||||||
definitions to find this out. Instantiating the latter definition with
|
|
||||||
<TT>F</TT> as <TT>int</TT> would result in:
|
|
||||||
<PRE>int::result_type negate(const int&);
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
where the return type is invalid. If this were an error, adding an unrelated function template
|
|
||||||
(that was never called) could break otherwise valid code.
|
|
||||||
Due to the SFINAE principle the above example is not, however, erroneous.
|
|
||||||
The latter definition of <TT>negate</TT> is simply removed from the overload resolution set.<BR>
|
|
||||||
<BR>
|
|
||||||
The <TT>enable_if</TT> templates are tools for controlled creation of the SFINAE
|
|
||||||
conditions.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC section The <TT>enable_if</TT> templates-->
|
|
||||||
|
|
||||||
<H2><A NAME="htoc4">2</A> The <TT>enable_if</TT> templates</H2><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="enable_if"></A>
|
|
||||||
The names of the <TT>enable_if</TT> templates have three parts: an optional <TT>lazy_</TT> tag,
|
|
||||||
either <TT>enable_if</TT> or <TT>disable_if</TT>, and an optional <TT>_c</TT> tag.
|
|
||||||
All eight combinations of these parts are supported.
|
|
||||||
The meaning of the <TT>lazy_</TT> tag is described in Section <A HREF="#sec:enable_if_lazy">3.3</A>.
|
|
||||||
The second part of the name indicates whether a true condition argument should
|
|
||||||
enable or disable the current overload.
|
|
||||||
The third part of the name indicates whether the condition argument is a <TT>bool</TT> value
|
|
||||||
(<TT>_c</TT> suffix), or a type containing a static <TT>bool</TT> constant named <TT>value</TT> (no suffix).
|
|
||||||
The latter version interoperates with Boost.MPL. <BR>
|
|
||||||
<BR>
|
|
||||||
The definitions of <TT>enable_if_c</TT> and <TT>enable_if</TT> are as follows (we use <TT>enable_if</TT> templates
|
|
||||||
unqualified but they are in the <TT>boost</TT> namespace).
|
|
||||||
<PRE>template <bool B, class T = void>
|
|
||||||
struct enable_if_c {
|
|
||||||
typedef T type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct enable_if_c<false, T> {};
|
|
||||||
|
|
||||||
template <class Cond, class T = void>
|
|
||||||
struct enable_if : public enable_if_c<Cond::value, T> {};
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
An instantiation of the <TT>enable_if_c</TT> template with the parameter
|
|
||||||
<TT>B</TT> as <TT>true</TT> contains a member type <TT>type</TT>, defined
|
|
||||||
to be <TT>T</TT>. If <TT>B</TT> is
|
|
||||||
<TT>false</TT>, no such member is defined. Thus
|
|
||||||
<TT>enable_if_c<B, T>::type</TT> is either a valid or an invalid type
|
|
||||||
expression, depending on the value of <TT>B</TT>.
|
|
||||||
When valid, <TT>enable_if_c<B, T>::type</TT> equals <TT>T</TT>.
|
|
||||||
The <TT>enable_if_c</TT> template can thus be used for controlling when functions are considered for
|
|
||||||
overload resolution and when they are not.
|
|
||||||
For example, the following function is defined for all arithmetic types (according to the
|
|
||||||
classification of the <A HREF="../type_traits/index.html">Boost type_traits library</A>):
|
|
||||||
<PRE>template <class T>
|
|
||||||
typename enable_if_c<boost::is_arithmetic<T>::value, T>::type
|
|
||||||
foo(T t) { return t; }
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
The <TT>disable_if_c</TT> template is provided as well, and has the
|
|
||||||
same functionality as <TT>enable_if_c</TT> except for the negated condition. The following
|
|
||||||
function is enabled for all non-arithmetic types.
|
|
||||||
<PRE>template <class T>
|
|
||||||
typename disable_if_c<boost::is_arithmetic<T>::value, T>::type
|
|
||||||
bar(T t) { return t; }
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
For easier syntax in some cases and interoperation with Boost.MPL we provide versions of
|
|
||||||
the <TT>enable_if</TT> templates taking any type with a <TT>bool</TT> member constant named
|
|
||||||
<TT>value</TT> as the condition argument.
|
|
||||||
The MPL <TT>bool_</TT>, <TT>and_</TT>, <TT>or_</TT>, and <TT>not_</TT> templates are likely to be
|
|
||||||
useful for creating such types. Also, the traits classes in the Boost.Type_traits library
|
|
||||||
follow this convention.
|
|
||||||
For example, the above example function <TT>foo</TT> can be alternatively written as:
|
|
||||||
<PRE>template <class T>
|
|
||||||
typename enable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t) { return t; }
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
|
|
||||||
<!--TOC section Using <TT>enable_if</TT>-->
|
|
||||||
|
|
||||||
<H2><A NAME="htoc5">3</A> Using <TT>enable_if</TT></H2><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:using_enable_if"></A>
|
|
||||||
The <TT>enable_if</TT> templates are defined in
|
|
||||||
<TT>boost/utility/enable_if.hpp</TT>, which is included by <TT>boost/utility.hpp</TT>.<BR>
|
|
||||||
<BR>
|
|
||||||
With respect to function templates, <TT>enable_if</TT> can be used in multiple different ways:
|
|
||||||
|
|
||||||
<UL>
|
|
||||||
<LI>As the return type of an instantiatied function
|
|
||||||
<LI>As an extra parameter of an instantiated function
|
|
||||||
<LI>As an extra template parameter (useful only in a compiler that supports C++0x default
|
|
||||||
arguments for function template parameters, see <A href="#sec:enable_if_0x">Enabling function
|
|
||||||
templates in C++0x</a> for details)
|
|
||||||
</UL>
|
|
||||||
|
|
||||||
In the previous section, the return type form of <TT>enable_if</TT> was shown. As an example
|
|
||||||
of using the form of <TT>enable_if</TT> that works via an extra function parameter, the
|
|
||||||
<TT>foo</TT> function in the previous section could also be written
|
|
||||||
as:
|
|
||||||
<PRE>template <class T>
|
|
||||||
T foo(T t, typename enable_if<boost::is_arithmetic<T> >::type* dummy = 0);
|
|
||||||
|
|
||||||
</PRE>Hence, an extra parameter of type <TT>void*</TT> is added, but it is given
|
|
||||||
a default value to keep the parameter hidden from client code.
|
|
||||||
Note that the second template argument was not given to <TT>enable_if</TT>, as the default
|
|
||||||
<TT>void</TT> gives the desired behavior.<BR>
|
|
||||||
<BR>
|
|
||||||
Which way to write the enabler is largely a matter of taste, but for certain functions, only a
|
|
||||||
subset of the options is possible:
|
|
||||||
<UL><LI>
|
|
||||||
Many operators have a fixed number of arguments, thus <TT>enable_if</TT> must be used either in the
|
|
||||||
return type or in an extra template parameter.
|
|
||||||
<LI>Functions that have a variadic parameter list must use either the return type form or an extra
|
|
||||||
template parameter.
|
|
||||||
<LI>Constructors do not have a return type so you must use either an extra function parameter or an
|
|
||||||
extra template parameter.
|
|
||||||
<LI>Constructors that have a variadic parameter list must an extra template parameter.
|
|
||||||
<LI>Conversion operators can only be written with an extra template parameter.
|
|
||||||
</UL>
|
|
||||||
<!--TOC subsection Enabling function templates in C++0x-->
|
|
||||||
|
|
||||||
<A NAME="sec:enable_if_0x"></A>
|
|
||||||
<H3><A NAME="htoc6">3.1</A> Enabling function templates in C++0x</H3><!--SEC END -->
|
|
||||||
|
|
||||||
In a compiler which supports C++0x default arguments for function template parameters, you can
|
|
||||||
enable and disable function templates by adding an additional template parameter. This approach
|
|
||||||
works in all situations where you would use either the return type form of <TT>enable_if</TT> or
|
|
||||||
the function parameter form, including operators, constructors, variadic function templates, and
|
|
||||||
even overloaded conversion operations.
|
|
||||||
|
|
||||||
As an example:
|
|
||||||
|
|
||||||
<PRE>#include <boost/type_traits/is_arithmetic.hpp>
|
|
||||||
#include <boost/type_traits/is_pointer.hpp>
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
|
|
||||||
class test
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// A constructor that works for any argument list of size 10
|
|
||||||
template< class... T
|
|
||||||
, typename boost::enable_if_c< sizeof...( T ) == 10, int >::type = 0
|
|
||||||
>
|
|
||||||
test( T&&... );
|
|
||||||
|
|
||||||
// A conversion operation that can convert to any arithmetic type
|
|
||||||
template< class T
|
|
||||||
, typename boost::enable_if< boost::is_arithmetic< T >, int >::type = 0
|
|
||||||
>
|
|
||||||
operator T() const;
|
|
||||||
|
|
||||||
// A conversion operation that can convert to any pointer type
|
|
||||||
template< class T
|
|
||||||
, typename boost::enable_if< boost::is_pointer< T >, int >::type = 0
|
|
||||||
>
|
|
||||||
operator T() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
// Works
|
|
||||||
test test_( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 );
|
|
||||||
|
|
||||||
// Fails as expected
|
|
||||||
test fail_construction( 1, 2, 3, 4, 5 );
|
|
||||||
|
|
||||||
// Works by calling the conversion operator enabled for arithmetic types
|
|
||||||
int arithmetic_object = test_;
|
|
||||||
|
|
||||||
// Works by calling the conversion operator enabled for pointer types
|
|
||||||
int* pointer_object = test_;
|
|
||||||
|
|
||||||
// Fails as expected
|
|
||||||
struct {} fail_conversion = test_;
|
|
||||||
}
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
|
|
||||||
<!--TOC subsection Enabling template class specializations-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc7">3.2</A> Enabling template class specializations</H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:enable_if_classes"></A>
|
|
||||||
Class template specializations can be enabled or disabled with <TT>enable_if</TT>.
|
|
||||||
One extra template parameter needs to be added for the enabler expressions.
|
|
||||||
This parameter has the default value <TT>void</TT>.
|
|
||||||
For example:
|
|
||||||
<PRE>template <class T, class Enable = void>
|
|
||||||
class A { ... };
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class A<T, typename enable_if<is_integral<T> >::type> { ... };
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class A<T, typename enable_if<is_float<T> >::type> { ... };
|
|
||||||
|
|
||||||
</PRE>Instantiating <TT>A</TT> with any integral type matches the first specialization,
|
|
||||||
whereas any floating point type matches the second one. All other types
|
|
||||||
match the primary template.
|
|
||||||
The condition can be any compile-time boolean expression that depends on the
|
|
||||||
template arguments of the class.
|
|
||||||
Note that again, the second argument to <TT>enable_if</TT> is not needed; the default (<TT>void</TT>)
|
|
||||||
is the correct value.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC subsection Overlapping enabler conditions-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc8">3.3</A> Overlapping enabler conditions</H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:overlapping_conditions"></A>
|
|
||||||
Once the compiler has examined the enabling conditions and included the
|
|
||||||
function into the overload resolution set, normal C++ overload resolution
|
|
||||||
rules are used to select the best matching function.
|
|
||||||
In particular, there is no ordering between enabling conditions.
|
|
||||||
Function templates with enabling conditions that are not mutually exclusive can
|
|
||||||
lead to ambiguities. For example:
|
|
||||||
<PRE>template <class T>
|
|
||||||
typename enable_if<boost::is_integral<T>, void>::type
|
|
||||||
foo(T t) {}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename enable_if<boost::is_arithmetic<T>, void>::type
|
|
||||||
foo(T t) {}
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
All integral types are also arithmetic. Therefore, say, for the call <TT>foo(1)</TT>,
|
|
||||||
both conditions are true and both functions are thus in the overload resolution set.
|
|
||||||
They are both equally good matches and thus ambiguous.
|
|
||||||
Of course, more than one enabling condition can be simultaneously true as long as
|
|
||||||
other arguments disambiguate the functions.<BR>
|
|
||||||
<BR>
|
|
||||||
The above discussion applies to using <TT>enable_if</TT> in class template
|
|
||||||
partial specializations as well.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC subsection Lazy <TT>enable_if</TT>-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc9">3.4</A> Lazy <TT>enable_if</TT></H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:enable_if_lazy"></A>
|
|
||||||
In some cases it is necessary to avoid instantiating part of a
|
|
||||||
function signature unless an enabling condition is true. For example:
|
|
||||||
<PRE>template <class T, class U> class mult_traits;
|
|
||||||
|
|
||||||
template <class T, class U>
|
|
||||||
typename enable_if<is_multipliable<T, U>, typename mult_traits<T, U>::type>::type
|
|
||||||
operator*(const T& t, const U& u) { ... }
|
|
||||||
|
|
||||||
</PRE>Assume the class template <TT>mult_traits</TT> is a traits class defining
|
|
||||||
the resulting type of a multiplication operator. The <TT>is_multipliable</TT> traits
|
|
||||||
class specifies for which types to enable the operator. Whenever
|
|
||||||
<TT>is_multipliable<A, B>::value</TT> is <TT>true</TT> for some types <TT>A</TT> and <TT>B</TT>,
|
|
||||||
then <TT>mult_traits<A, B>::type</TT> is defined.<BR>
|
|
||||||
<BR>
|
|
||||||
Now, trying to invoke (some other overload) of <TT>operator*</TT> with, say, operand types <TT>C</TT> and <TT>D</TT>
|
|
||||||
for which <TT>is_multipliable<C, D>::value</TT> is <TT>false</TT>
|
|
||||||
and <TT>mult_traits<C, D>::type</TT> is not defined is an error on some compilers.
|
|
||||||
The SFINAE principle is not applied because
|
|
||||||
the invalid type occurs as an argument to another template. The <TT>lazy_enable_if</TT>
|
|
||||||
and <TT>lazy_disable_if</TT> templates (and their <TT>_c</TT> versions) can be used in such
|
|
||||||
situations:
|
|
||||||
<PRE>template<class T, class U>
|
|
||||||
typename lazy_enable_if<is_multipliable<T, U>, mult_traits<T, U> >::type
|
|
||||||
operator*(const T& t, const U& u) { ... }
|
|
||||||
|
|
||||||
</PRE>The second argument of <TT>lazy_enable_if</TT> must be a class type
|
|
||||||
that defines a nested type named <TT>type</TT> whenever the first
|
|
||||||
parameter (the condition) is true.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC paragraph Note-->
|
|
||||||
|
|
||||||
<H5>Note</H5><!--SEC END -->
|
|
||||||
|
|
||||||
Referring to one member type or static constant in a traits class
|
|
||||||
causes all of the members (type and static constant) of that
|
|
||||||
specialization to be instantiated. Therefore, if your traits classes
|
|
||||||
can sometimes contain invalid types, you should use two distinct
|
|
||||||
templates for describing the conditions and the type mappings. In the
|
|
||||||
above example, <TT>is_multipliable<T, U>::value</TT> defines when
|
|
||||||
<TT>mult_traits<T, U>::type</TT> is valid.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC subsection Compiler workarounds-->
|
|
||||||
|
|
||||||
<H3><A NAME="htoc10">3.5</A> Compiler workarounds</H3><!--SEC END -->
|
|
||||||
|
|
||||||
<A NAME="sec:workarounds"></A>
|
|
||||||
Some compilers flag functions as ambiguous if the only distinguishing factor is a different
|
|
||||||
condition in an enabler (even though the functions could never be ambiguous). For example,
|
|
||||||
some compilers (e.g. GCC 3.2) diagnose the following two functions as ambiguous:
|
|
||||||
<PRE>template <class T>
|
|
||||||
typename enable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename disable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t);
|
|
||||||
|
|
||||||
</PRE>Two workarounds can be applied:
|
|
||||||
<UL><LI>
|
|
||||||
Use an extra dummy parameter which disambiguates the functions. Use a default value for
|
|
||||||
it to hide the parameter from the caller. For example:
|
|
||||||
<PRE>template <int> struct dummy { dummy(int) {} };
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename enable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t, dummy<0> = 0);
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
typename disable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t, dummy<1> = 0);
|
|
||||||
</PRE><BR>
|
|
||||||
<BR>
|
|
||||||
<LI>Define the functions in different namespaces and bring them into a common
|
|
||||||
namespace with <TT>using</TT> declarations:
|
|
||||||
<PRE>namespace A {
|
|
||||||
template <class T>
|
|
||||||
typename enable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t);
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace B {
|
|
||||||
template <class T>
|
|
||||||
typename disable_if<boost::is_arithmetic<T>, T>::type
|
|
||||||
foo(T t);
|
|
||||||
}
|
|
||||||
|
|
||||||
using A::foo;
|
|
||||||
using B::foo;
|
|
||||||
|
|
||||||
</PRE>
|
|
||||||
Note that the second workaround above cannot be used for member
|
|
||||||
templates. On the other hand, operators do not accept extra arguments,
|
|
||||||
which makes the first workaround unusable. As the net effect,
|
|
||||||
neither of the workarounds are of assistance for templated operators that
|
|
||||||
need to be defined as member functions (assignment and
|
|
||||||
subscript operators).
|
|
||||||
</UL>
|
|
||||||
<!--TOC section Acknowledgements-->
|
|
||||||
|
|
||||||
<H2><A NAME="htoc11">4</A> Acknowledgements</H2><!--SEC END -->
|
|
||||||
|
|
||||||
We are grateful to Howard Hinnant, Jason Shirk, Paul Mensonides, and Richard
|
|
||||||
Smith whose findings have influenced the library.<BR>
|
|
||||||
<BR>
|
|
||||||
<!--TOC section References-->
|
|
||||||
|
|
||||||
<H2>References</H2><!--SEC END -->
|
|
||||||
<DL COMPACT=compact><DT><A NAME="jarvi:03:cuj_arbitrary_overloading"><FONT COLOR=purple>[1]</FONT></A><DD>
|
|
||||||
Jaakko Järvi, Jeremiah Willcock, Howard Hinnant, and Andrew Lumsdaine.
|
|
||||||
Function overloading based on arbitrary properties of types.
|
|
||||||
<EM>C/C++ Users Journal</EM>, 21(6):25--32, June 2003.<BR>
|
|
||||||
<BR>
|
|
||||||
<DT><A NAME="jarvi:03:c++typeclasses"><FONT COLOR=purple>[2]</FONT></A><DD>
|
|
||||||
Jaakko Järvi, Jeremiah Willcock, and Andrew Lumsdaine.
|
|
||||||
Concept-controlled polymorphism.
|
|
||||||
In Frank Pfennig and Yannis Smaragdakis, editors, <EM>Generative
|
|
||||||
Programming and Component Engineering</EM>, volume 2830 of <EM>LNCS</EM>, pages
|
|
||||||
228--244. Springer Verlag, September 2003.<BR>
|
|
||||||
<BR>
|
|
||||||
<DT><A NAME="vandevoorde2002:templates"><FONT COLOR=purple>[3]</FONT></A><DD>
|
|
||||||
David Vandevoorde and Nicolai M. Josuttis.
|
|
||||||
<EM>C++ Templates: The Complete Guide</EM>.
|
|
||||||
Addison-Wesley, 2002.</DL>
|
|
||||||
|
|
||||||
<hr/>
|
|
||||||
<p>Copyright Jaakko Järvi<sup>*</sup>, Jeremiah Willcock<sup>*</sup>, Andrew Lumsdaine<sup>*</sup>, Matt Calabrese<BR>
|
|
||||||
<EM>{jajarvi|jewillco|lums}@osl.iu.edu, rivorus@gmail.com</EM><BR>
|
|
||||||
<sup>*</sup>Indiana University<BR>
|
|
||||||
Open Systems Lab<br/>
|
|
||||||
Use, modification and distribution are subject to the
|
|
||||||
Boost Software License, Version 1.0.
|
|
||||||
(See accompanying file LICENSE_1_0.txt
|
|
||||||
or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">
|
|
||||||
http://www.boost.org/LICENSE_1_0.txt
|
|
||||||
</a>).
|
|
||||||
</p>
|
|
||||||
<!--HTMLFOOT-->
|
|
||||||
<!--ENDHTML-->
|
|
||||||
<!--FOOTER-->
|
|
||||||
<HR SIZE=2>
|
|
||||||
<BLOCKQUOTE><EM>This document was translated from L<sup>A</sup>T<sub>E</sub>X by
|
|
||||||
</EM><A HREF="http://pauillac.inria.fr/~maranget/hevea/index.html"><EM>H<FONT SIZE=2><sup>E</sup></FONT>V<FONT SIZE=2><sup>E</sup></FONT>A</EM></A><EM>.
|
|
||||||
</EM></BLOCKQUOTE>
|
|
||||||
</BODY>
|
|
||||||
</HTML>
|
|
Reference in New Issue
Block a user