O''''Reilly Network For Information About''''s Book part 52 - Pdf 17

addressof
Header:
"boost/utility.hpp"
When taking the address of a variable, we typically depend on the returned value to
be, well, the address of the variable. However, it's technically possible to overload
operator&, which means that evildoers may be on a mission to wreak havoc on
your address-dependent code. boost::addressof is provided to get the
address anyway, regardless of potential uses and misuses of operator overloading.
By using some clever internal machinery, the template function addressof
ensures that it gets to the actual object and its address.
Usage
To always be sure to get the real address of an object, use boost::addressof.
It is defined in "boost/utility.hpp". It is used where operator& would
otherwise be used, and it accepts an argument that is a reference to the type whose
address should be taken.
#include "boost/utility.hpp"
class some_class {};
int main() {
some_class s;
some_class* p=boost::addressof(s);
}
Before seeing more details on how to use addressof, it is helpful to understand
why and how operator& may not actually return the address of an object.
Quick Lesson for Evildoers
If you really, really, really need to overload operator&, or just want to
experiment with the potential uses of operator overloading, it's actually quite easy.
When overloading operator&, the semantics are always different from what
most users (and functions!) expect, so don't do it just to be cute; do it for a very
good reason or not at all. That said, here's a code-breaker for you:
class codebreaker {
public:

Also known as an ingenious hack.
template <typename T> void print_address(const T& t) {
std::cout << "&t: " << (&t) << '\n';
std::cout << "addressof(t): " << boost::addressof(t) << '\n';
}
When invoked, the function gives this output (or similar, because the exact address
differs depending upon your system).
&t: 13
addressof(t): 0012FECB13
That's more like it! If there are scenarios where you know, or suspect, that
operator& is provided by a class but you need to be really sure that you get the
actual address (which is unlikely for an overloaded operator& or why else
would it be overloaded in the first place?), use addressof.
Summary

There are not many potent arguments for overloading operator&,
[7]
but because
it is possible, some people do it anyway. When writing code that relies on
retrieving the actual address of objects, addressof can help by ensuring that the
real address is returned. When writing generic code, there is no way of telling
which types will be operated upon, so if the address of parameterized types needs
to be taken, use addressof.
[7]
Custom hardware device drivers notwithstanding.
Use addressof when you must retrieve the actual address of an object,
regardless of the semantics for operator&.

template <typename T> void some_func(T t) {
typename T::type variable_of_nested_type;
std::cout <<
"template <typename T> void some_func(" << t << ")\n";
}
int main() {
int i=12;
short s=12;
some_func(i);
some_func(s);
}
When compiling this program, you will get something like the following output
from the frustrated compiler:
enable_if_sample1.cpp: In function 'void some_func(T)
[with T = short int]':
enable_if_sample1.cpp:17: instantiated from here
enable_if_sample1.cpp:8: error:
'short int' is not a class, struct, or union type
Compilation exited abnormally with code 1 at Sat Mar 06 14:30:08
There it is. The template version of some_func has been chosen as the best
overload, but the code in that version is not valid for the type short. How could
we have avoided this? Well, we would have liked to only enable the template
version of some_func for types with a nested type named type, and to ignore it
for those without it. We can do that. The easiest way, which is not always an
option in real life, is to change the return type of the template version like so:
template <typename T> typename T::type* some_func(T t) {
typename T::type variable_of_nested_type;
std::cout <<
"template <typename T> void some_func(" << t << ")\n";
return 0;

void some_func(12)
void some_func(12)
template <typename T> void some_func(T t)
This works, but it's not a pretty sight. In this scenario, we had the luxury of playing
with a void
return type, which we could use for other purposes. If that hadn't been
the case, we could have added another argument to the function and given it a
default value.
template <typename T>
void some_func(T t,typename T::type* p=0) {
typename T::type variable_of_nested_type;
std::cout << "template <typename T> void some_func(T t)\n";
}
This version al
so uses SFINAE to disqualify itself from use with invalid types. The
problem with both of these solutions is that they're really ugly, we have made them
a part of the public interface, and they only work in some scenarios. Boost offers a
much cleaner solution, which is both syntactically nicer and offers a much wider
range of functionality than our earlier ad hoc solutions.
Usage
To use enable_if and disable_if, include
"boost/utility/enable_if.hpp"
. For the first example, we'll disable the
second version of some_func if the type of the argument is integral. Type
information such as whether a type is integral is available in another Boost library,
Boost.Type_traits. The enable_if and disable_if templates both
accept a predicate controlling whether to enable or disable the function,
respectively.
#include <iostream>
#include "boost/utility/enable_if.hpp"

std::cout << "void some_func(" << i << ")\n";
}
template <typename T> void some_func(T t,
typename boost::enable_if<has_type<T> >::type* p=0) {
typename T::type variable_of_nested_type;
std::cout << "template <typename T> void some_func(T t)\n";
}
This is very cool indeed! We are now disabling the template version of
some_func when there is no nested type, type, in T, and we explicitly
document that this is a requirement for the function in its signature. The trick here
is to use a very nifty feature of Boost.Mpl that can test whether a certain nested
type (or typedef) exists in an arbitrary type T. Using the macro invocation,
BOOST_MPL_HAS_XXX_TRAIT_DEF(type), we define a new trait called
has_type, which we use in the function some_func as the predicate for
enable_if. If the predicate yields TRue, the function is part of the ov
erload set;
if it yields false, it is excluded.
It's also possible to wrap the return type rather than add an extra (defaulted)
argument. The equivalent of our latest and greatest some_func, but using
enable_if in the return type, looks like this.
template <typename T> typename
boost::enable_if<has_type<T>,void>::type
some_func(T t) {
typename T::type variable_of_nested_type;
std::cout << "template <typename T> void some_func(T t)\n";
}
If you need to return the type that you need to enable or disable on, using
enable_if and disable_if on the return type makes more sense than adding
a defaulted argument. Also, there is a chance that someone actually provides a
value instead of that default argument, which breaks the code. Sometimes, class

typename boost::enable_if<boost::is_arithmetic<T> >::type> {
public:
T max() const {
std::cout << "some_class::max() with an arithmetic type\n";
return std::numeric_limits<T>::max();
}
};
This version is only enabled when instantiated with a type that is arithmeticthat is,
when the trait is_arithmetic yields true. This works because
boost::enable_if<false>::type is void, matching the primary
template specialization. The following program tests these templates with various
types:
#include <iostream>
#include <string>
#include <limits>
#include "boost/utility/enable_if.hpp"
#include "boost/type_traits.hpp"
// Definition of the template some_class omitted
int main() {
std::cout << "Max for std::string: " <<
some_class<std::string>().max() << '\n';
std::cout << "Max for void: " <<
some_class<void>().max() << '\n';
std::cout << "Max for short: " <<
some_class<short>().max() << '\n';
std::cout << "Max for int: " <<
some_class<int>().max() << '\n';
std::cout << "Max for long: " <<
some_class<long>().max() << '\n';
std::cout << "Max for double: " <<

typename boost::enable_if_c<
boost::is_arithmetic<T>::value>::type> {
public:
T max() const {
std::cout << "some_class::max() with an arithmetic type\n";
return std::numeric_limits<T>::max();
}
};
There is no fundamental difference between enable_if and enable_if_c.
It's only the expectation of a nested type value that sets them apart.
Summary

The C++ language feature known as SFINAE is important. Without it, a lot of new
code would break existing code, and some types of function overloads (and
template specializations) would simply not be possible. To directly make use of
SFINAE in a controlled way to enable or disable certain functions or types for
overload resolution is complicated. It also makes for hard-to-read code. Using
boost::enable_if is an elegant way of simultaneously stating that an
overload is only eligible when certain conditions apply. The same argument holds
for disable_if, which is used to state the oppositethat an overload is not
applicable if the condition holds true. There is promise of even more practical uses
of SFINAE, and this library also serves as a very nice introduction of the topic.
This chapter has omitted the lazy versions of enable_if and disable_if
(named lazy_enable_if and lazy_disable_if), but I'll give them a brief
mention here. The lazy versions are used to avoid instantiating types that may not
be available (depending on the value of the condition).
Use enable_if when:

You need to add or remove a function to the overload set depending on some
condition


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status