new docs and optimization

[SVN r2610]
This commit is contained in:
Arkadiy Vertleyb
2005-06-03 02:11:33 +00:00
parent b7534ac092
commit bd6c0e07c4
13 changed files with 962 additions and 165 deletions

7
doc/Jamfile.v2 Executable file
View File

@ -0,0 +1,7 @@
#project boost/doc ;
project root ;
import boostbook : boostbook ;
boostbook typeof : typeof.xml ;

6
doc/project-root.jam Executable file
View File

@ -0,0 +1,6 @@
path-constant BOOST_ROOT : . ;
#using lex ;
#using bison ;
#using testing ;

871
doc/typeof.qbk Executable file
View File

@ -0,0 +1,871 @@
[library Typeof
[authors [Vertleyb, Arkadiy], [Holt, Peder]]
[copyright 2004 2005 Arkadiy Vertleyb, Peder Holt]
[license
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
<ulink url="http://www.boost.org/LICENSE_1_0.txt">
http://www.boost.org/LICENSE_1_0.txt
</ulink>)
]
]
[xinclude catalog.xml]
[section:moti Motivation]
[c++]
Today many template libraries supply object generators to simplify object creation
by utilizing the C++ template argument deduction facility. Consider `std::pair`.
In order to instantiate this class template and create a temporary object of this instantiation,
one has to supply both type parameters and value parameters:
std::pair<int, double>(5, 3.14159);
To avoid this duplication, STL supplies the `std::make_pair` object generator.
When it is used, the types of template parameters are deduced from supplied function arguments:
std::make_pair(5, 3.14159);
For the temporary objects it is enough. However, when a named object needs to be allocated,
the problem appears again:
std::pair<int, double> p(5, 3.14159);
The object generator no longer helps:
std::pair<int, double> p = std::make_pair(5, 3.14159);
It would be nice to deduce the type of the object (on the left) from the expression
it is initialized with (on the right), but the current C++ syntax does not allow for this.
The above example demonstrates the essence of the problem but does not demonstrate its scale.
Many libraries, especially expression template libraries, create objects of really complicated types,
and go a long way to hide this complexity behind object generators. Consider a nit Boost.Lambda functor:
_1 > 15 && _2 < 20
If one wanted to allocate a named copy of such an innocently looking functor,
she would have to specify something like this:
lambda_functor<
lambda_functor_base<
logical_action<and_action>,
tuple<
lambda_functor<
lambda_functor_base<
relational_action<greater_action>,
tuple<
lambda_functor<placeholder<1> >,
int const
>
>
>,
lambda_functor<
lambda_functor_base<
relational_action<less_action>,
tuple<
lambda_functor<placeholder<2> >,
int const
>
>
>
>
>
>
f = _1 > 15 && _2 < 20;
Not exactly elegant. To solve this problem, the C++ standard committee is considering
a few additions to the standard language, such as `typeof/decltype` and `auto` (see
[@http://www.osl.iu.edu/~jajarvi/publications/papers/decltype_n1478.pdf
http://www.osl.iu.edu/~jajarvi/publications/papers/decltype_n1478.pdf]).
The `typeof` operator (or `decltype`, which is a slightly different flavor of `typeof`)
allows one to determine the type of an expression at compile time. Using `typeof`,
the above example can be simplified drastically:
typeof(_1 > 15 && _2 < 20) f = _1 > 15 && _2 < 20;
Much better, but some duplication still exists. The `auto` type solves the rest of the problem:
auto f = _1 > 15 && _2 < 20;
[endsect]
[section:tuto Tutorial]
To deduce the type of an expression at compile time
use the `BOOST_TYPEOF` macro:
namespace ex1
{
typedef BOOST_TYPEOF(1 + 0.5) type;
BOOST_STATIC_ASSERT((is_same<type, double>::value));
}
In the dependent context use `BOOST_TYPEOF_TPL` instead of `BOOST_TYPEOF`:
namespace ex2
{
template<class T, class U>
BOOST_TYPEOF_TPL(T() + U()) add(const T& t, const U& u)
{
return t + u;
};
typedef BOOST_TYPEOF(add('a', 1.5)) type;
BOOST_STATIC_ASSERT((is_same<type, double>::value));
}
The above examples are possible because the Typeof Library knows about
primitive types, such as `int`, `double`, `char`, etc. The Typeof Library also
knows about most types and templates defined by the
Standard C++ Library, but the appropriate headers need to be included
to take advantage of this:
#include <boost/typeof/std/utility.hpp>
namespace ex3
{
BOOST_AUTO(p, make_pair(1, 2));
BOOST_STATIC_ASSERT((is_same<BOOST_TYPEOF(p), pair<int, int> >::value));
}
Here `<boost/typeof/std/utility.hpp>` includes `<utility>` and contains
knowledge about templates defined there. This naming convention
applies in general, for example to let the Typeof Library handle `std::vector`,
include `<boost/typeof/std/vector.hpp>`, etc.
To deduce the type of a variable from the expression, this variable
is initialized with, use the `BOOST_AUTO` macro (or `BOOST_AUTO_TPL`
in a dependent context:
#include <boost/typeof/std/string.hpp>
namespace ex4
{
BOOST_AUTO(p, new int[20]);
BOOST_STATIC_ASSERT((is_same<BOOST_TYPEOF(p), int*>::value));
}
Both `BOOST_TYPEOF` and `BOOST_AUTO` strip top-level qualifiers.
Therefore, to allocate a reference, this has to be defined explicitly:
namespace ex5
{
string& hello()
{
static string s = "hello";
return s;
}
BOOST_AUTO(&s, hello());
}
To better understand this syntax, note that this gets expanded into:
BOOST_TYPEOF(hello()) &s = hello();
If your define your own type, the Typeof Library cannot handle it
unless you let it know about this type. You tell the Typeof Library
about a type (or template) by the means of "registering" this type/template.
Any source or header file where types/templates are registered should
contain the following line before any registration is done:
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
After this a type can be registered:
namespace ex6
{
struct MyType
{};
}
BOOST_TYPEOF_REGISTER_TYPE(ex6::MyType)
The registration should be done from the context of global namespace;
fully qualified type name has to be used.
Any number of types can be registered in one file, each on a separate line.
Once your type is registered, the Typeof Library can handle it in any context:
namespace ex6
{
typedef BOOST_TYPEOF(make_pair(1, MyType())) type;
BOOST_STATIC_ASSERT((is_same<type, pair<int, MyType> >::value));
}
A template is registered by specifying its fully qualified name,
and describing its parameters. In the simplest case, when all parameters
are type parameters, only their number needs to be specified:
namespace ex7
{
template<class T, class U>
struct MyTemplate
{};
}
BOOST_TYPEOF_REGISTER_TEMPLATE(ex7::MyTemplate, 2)
namespace ex7
{
typedef BOOST_TYPEOF(make_pair(1, MyTemplate<int, ex6::MyType>())) type;
BOOST_STATIC_ASSERT((is_same<type,
pair<int, MyTemplate<int, ex6::MyType> >
>::value));
}
When a template has integral template parameters, all parameters need
to be described in the preprocessor sequence:
namespace ex8
{
template<class T, int n>
struct MyTemplate
{};
}
BOOST_TYPEOF_REGISTER_TEMPLATE(ex8::MyTemplate, (class)(int))
namespace ex8
{
typedef BOOST_TYPEOF(make_pair(1, MyTemplate<ex7::MyTemplate<ex6::MyType, int>, 0>())) type;
BOOST_STATIC_ASSERT((is_same<type,
pair<int, MyTemplate<ex7::MyTemplate<ex6::MyType, int>, 0> >
>::value));
}
Please see the reference for more details.
[endsect]
[section:refe Reference]
[section:auto AUTO, AUTO_TPL]
The `BOOST_AUTO` macro emulates the proposed `auto` keyword in C++.
[h4 Usage]
BOOST_AUTO(var,expr)
BOOST_AUTO_TPL(var,expr)
[variablelist Arguments
[[var][a free identifier]]
[[expr][a valid c++ expression that has a type]]
]
[h4 Remarks]
If you want to use `auto` in a template-context, use `BOOST_AUTO_TPL(expr)`,
which takes care of `typename` inside the `auto` expression.
[h4 Sample Code]
void main()
{
length::meter a(5);
force::newton b(6);
BOOST_AUTO(c, a * b);
}
[endsect]
[section:compl COMPLIANT]
The `BOOST_TYPEOF_COMPLIANT` macro can be used to force the emulation mode.
Define it if your compiler by default uses another mode, such as native `typeof`
or Microsoft-specific trick, but you want to use the emulation mode,
for example for portability reasons.
[endsect]
[section:incr INCREMENT_REGISTRATION_GROUP]
The `BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP` macro ensures that type registrations
in different header files receive unique identifiers.
[h4 Usage]
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
[h4 Remarks]
specified once in every cpp/hpp file where any registration is performed,
before any registration.
[h4 Sample Code]
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
class X;
BOOST_TYPEOF_REGISTER_TYPE(X)
[endsect]
[section:inte INTEGRAL]
The `BOOST_TYPEOF_INTEGRAL` macro is used when registering an integral
template parameter using `BOOST_TYPEOF_REGISTER_TEMPLATE`.
Useful for `enum`s and dependent integral template parameters.
[h4 Usage]
BOOST_TYPEOF_INTEGRAL(x)
[variablelist Arguments
[[x][a fully qualified integral type or enum]]
]
[h4 Remarks]
A short syntax has been implemented for the built in types
(int, bool, long, unsigned long, etc.)
[h4 Sample Code]
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
namespace foo
{
enum color {red, green, blue};
template<color C0,typename T1>
class class_with_enum {};
template<typename T0,T0 I1>
class class_with_dependent_non_type {};
}
BOOST_TYPEOF_REGISTER_TEMPLATE(foo::class_with_enum,
(BOOST_TYPEOF_INTEGRAL(foo::color))
(typename)
)
BOOST_TYPEOF_REGISTER_TEMPLATE(foo::class_with_dependent_non_type,
(typename)
(BOOST_TYPEOF_INTEGRAL(P0))
)
[endsect]
[section:limit_func LIMIT_FUNCTION_ARITY]
The `BOOST_TYPEOF_LIMIT_FUNCTION_ARITY` macro defines how many parameters
are supported for functios, and applies to functions, function pointers,
function references, and member function pointers. The default value is 10.
Redefine if you want the Typeof Library to handle functions with more parameters.
[endsect]
[section:limit_size LIMIT_SIZE]
The `BOOST_TYPEOF_LIMIT_SIZE` macro defines the size of the compile-time sequence
used to encode a type. The default value is 50. Increase it if you want
the Typeof Library to handle very complex types, although this
possibility is limited by the maximum number of template parameters supported
by your compiler. On the other hand, if you work only with very simple types,
decreasing this number may help to boost compile-time performance.
[endsect]
[section:lval LVALUE_TYPEOF]
The `BOOST_LVALUE_TYPEOF` macro preserves the L-valueness of an expression.
[h4 Usage]
BOOST_LVALUE_TYPEOF(expr)
[variablelist Arguments
[[expr][a valid c++ expression that has a type]]
]
[h4 Remarks]
This macro attempts to emulate the `decltype`. Its rules, however,
are directly built on the rules of binding a reference, and therefore
differ from the ones of real `decltype`:
[table rules of LVALUE_TYPEOF
[[expr][decltype][LVALUE_TYPEOF]]
[[int i;][int][int&]]
[[const int ci = 0;][const int][const int&]]
[[int& ri = i;][int&][int&]]
[[const int& cri = ci;][const int&][const int&]]
[[int foo();][int][int]]
[[const int foo();][const int][const int&]]
[[int& foo();][int&][int&]]
[[const int& foo();][const int&][const int&]]
[[21][int][compiler-dependent]]
[[int(21)][int][int]]
]
[h4 Sample Code]
int& get_value(int& a);
int get_value(const double& a);
void main()
{
int a=5;
typedef BOOST_LVALUE_TYPEOF(get_value(a)) type;
}
[endsect]
[section:regtype REGISTER_TYPE]
The `BOOST_TYPEOF_REGISTER_TYPE` macro informs the Typeof Library
about the existence of a type
[h4 Usage]
BOOST_TYPEOF_REGISTER_TYPE(x)
[variablelist Arguments
[[x][a fully qualified type]]
]
[h4 Remarks]
Must be used in the global namespace
[h4 Sample Code]
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
namespace foo
{
class bar {};
enum color {red, green, blue};
}
BOOST_TYPEOF_REGISTER_TYPE(foo::bar)
BOOST_TYPEOF_REGISTER_TYPE(foo::color)
[endsect]
[section:regtemp REGISTER_TEMPLATE]
The `BOOST_TYPEOF_REGISTER_TEMPLATE` macro informs the Typeof Library
about the existence of a template and describes its parameters
[h4 Usage]
BOOST_TYPEOF_REGISTER_TEMPLATE(x, n)
BOOST_TYPEOF_REGISTER_TEMPLATE(x, seq)
[variablelist Arguments
[[x][a fully qualified template]]
[[n][the number of template arguments. Only valid if all template arguments are typenames]]
[[seq][a sequence of template arguments. Must be used when integral or template template parameters are present]]
]
[h4 Remarks]
Must be used in the global namespace.
The library allows registration of templates with type, integral,
and template template parameters:
* A type template parameter is described by the `(class)` or `(typename)` sequence element
* A template parameter of a well-known integral type can be described by
simply supplying its type, like `(unsigned int)`.
The following well-known integral types are supported:
* `[signed/unsigned] char`
* `[unsigned] short`
* `[unsigned] int`
* `[unsigned] long`
* `unsigned`
* `bool`
* `size_t`
* Other integral types, such as enums, need to be described explicitly
with the `BOOST_TYPEOF_INTEGRAL` macro, like `(BOOST_TYPEOF_INTEGRAL(MyEnum))`
* Template template parameters are described with the `BOOST_TYPEOF_TEMPLATE` macro,
like: `(BOOST_TYPEOF_TEMPLATE((class)(unsigned int)))`.
In case of all type parameters this can be shortened to something like `(BOOST_TYPEOF_TEMPLATE(2))`.
The nested template template parameters are not supported.
[h4 Sample Code]
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
namespace foo
{
template<typename T0, typename T1>
class simple_template {};
template<typename T0, int I1>
class class_with_integral_constant {};
}
BOOST_TYPEOF_REGISTER_TEMPLATE(foo::simple_template, 2)
BOOST_TYPEOF_REGISTER_TEMPLATE(foo::class_with_integral_constant, (typename)(int))
[endsect]
[section:temp TEMPLATE]
The `BOOST_TYPEOF_TEMPLATE` macro is used when registering template template parameters
using `BOOST_TYPEOF_REGISTER_TEMPLATE`.
[h4 Usage]
BOOST_TYPEOF_TEMPLATE(n)
BOOST_TYPEOF_TEMPLATE(seq)
[variablelist Arguments
[[n][the number of template arguments. Only valid if all template arguments are typenames]]
[[seq][a sequence of template arguments. Must be used when there are integral constants in the nested template]]
]
[h4 Remarks]
Can not be used to register nested template template parameters.
[h4 Sample Code]
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
namespace foo
{
enum color {red, green, blue};
template<color C0, template<typename> class T1>
class nested_template_class {};
template<template<typename, unsigned char> class T1>
class nested_with_integral {};
}
BOOST_TYPEOF_REGISTER_TEMPLATE(foo::nested_template_class,
(foo::color)
(BOOST_TYPEOF_TEMPLATE(1))
)
BOOST_TYPEOF_REGISTER_TEMPLATE(foo::nested_with_integral,
(BOOST_TYPEOF_TEMPLATE((typename)(unsigned char)))
)
[endsect]
[section:typo TYPEOF, TYPEOF_TPL]
The `BOOST_TYPEOF` macro calculates the type of an expression,
but removes the top-level qualifiers, `const&`
[h4 Usage]
BOOST_TYPEOF(expr)
BOOST_TYPEOF_TPL(expr)
[variablelist Arguments
[[expr][a valid c++ expression that has a type]]
]
[h4 Remarks]
If you want to use `typeof` in a template-context, use `BOOST_TYPEOF_TPL(expr)`,
which takes care of `typename` inside the `typeof` expression.
[h4 Sample Code]
template<typename A, typename B>
struct result_of_conditional
{
typedef BOOST_TYPEOF_TPL(true?A():B()) type;
};
template<typename A, typename B>
result_of_conditional<A, B>::type min(const A& a,const B& b)
{
return a < b ? a : b;
}
[endsect]
[endsect]
[section:other Other considerations and tips]
[section:natem Native typeof support and emulation]
Many compilers support typeof already, most noticeable GCC and Metrowerks.
Igor Chesnokov recently discovered a method that allows to implement `typeof`
on the VC series of compilers. It uses a bug in the Microsoft compiler
that allows a nested class of base to be defined in a class derived from base:
template<int ID> struct typeof_access
{
struct id2type; //not defined
};
template<class T, int ID> struct typeof_register : typeof_access
{
// define base's nested class here
struct typeof_access::id2type
{
typedef T type;
};
};
//Type registration function
typeof_register<T, compile-time-constant> register_type(const T&);
//Actually register type by instantiating typeof_register for the correct type
sizeof(register_type(some-type));
//Use the base class to access the type.
typedef typeof_access::id2type::type type;
This method has also been adapted to VC7.0, where the nested class
is a template class that is specialized in the derived class.
The loopholes have been fixed in VC8.0 though, so on this compiler
this method doesn't work.
For this and many other compilers neither native `typeof` support
nor the trick described above is an option. For such compilers
the emulation method is the only way of implementing `typeof`.
According to a rough estimate, at the time of this writing
the introduction of the `typeof`, `auto`, etc., into the C++ standard
may not happen soon. Even after it's done, some time still has to pass
before most compilers implement this feature. But even after that,
there always are legacy compilers to support (for example now, in 2005,
many people are still using VC6, long after VC7.x, and even VC8.0 beta became available).
Considering extreme usefulness of the feature right now,
it seems to make sense to implement it at the library level.
The emulation mode seems to be important even if a better option is present
on some particular compiler. If a library author wants to develop portable
code using `typeof`, she needs to use emulation mode and register her types and
templates. Those users who have a better option can still take
advantage of it, since the registration macros are defined as no-op on
such compilers, while the users for whom emulation is the only option will use it.
The other consideration applies to the users of VC7.1. Even though the more
convenient `typeof` trick is available, the possibility of upgrade to VC8,
where emulation remains the only option, should be considered.
The emulation mode can be forced on the compilers that don't use it
by default by defining the `BOOST_TYPEOF_COMPLIANT` symbol:
g++ -D BOOST_TYPEOF_COMPLIANT -I \boost\boost_1_32_0 main.cpp
[endsect]
[section:parties The three participating parties]
The Lambda example from the Motivation section requires the following registration:
#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP()
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::tuples::tuple, 2);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::lambda_functor, 1);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::lambda_functor_base, 2);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::relational_action, 1);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::logical_action, 1);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::other_action, 1);
BOOST_TYPEOF_REGISTER_TYPE(boost::lambda::greater_action);
BOOST_TYPEOF_REGISTER_TYPE(boost::lambda::less_action);
BOOST_TYPEOF_REGISTER_TYPE(boost::lambda::and_action);
BOOST_TYPEOF_REGISTER_TEMPLATE(boost::lambda::placeholder, (int));
It may seem that the price for the ability to discover the expression's type
is too high: rather large amount of registration is required.
However note that all of the above registration is done only once,
and after that, any combination of the registered types and templates
would be handled. Moreover, this registration is typically done
not by the end-user, but rather by a layer on top of some library
(in this example -- Boost.Lambda).
When thinking about this, it's helpful to consider three parties: the typeof facility,
the library (probably built on expression templates principle), and the end-user.
The typeof facility is responsible for registering fundamental types.
The library can register its own types and templates.
In the best-case scenario, if the expressions always consist of only
fundamental types and library-defined types and templates, a library author
can achieve the impression that the `typeof` is natively supported for her library.
On the other hand, the more often expressions contain user-defined types,
the more responsibility is put on the end-user, and therefore the less attractive
this approach becomes.
Thus, the ratio of user-defined types in the expressions should be the main
factor to consider when deciding whether or not to apply the typeof facility.
[endsect]
[section:features Supported features]
The Typeof library pre-registers fundamental types. For these types,
and for any other types/templates registered by the user library or end-user,
any combination of the following is supported:
* Pointers;
* References (except top-level);
* Consts (except top-level);
* Volatiles (except top-level);
* Arrays;
* Functions, function pointers, and references;
* Pointers to member functions;
* Pointers to data members.
For example the following type:
int& (*)(const volatile char*, double[5], void(*)(short))
is supported right away, and something like:
void (MyClass::*)(int MyClass::*, MyClass[10]) const
is supported provided `MyClass` is registered.
The Typeof Library also provides registration files for most STL classes/templates.
These files are located in the std subdirectory, and named after corresponding STL headers.
These files are not included by the typeof system and have to be explicitly included
by the user, as needed:
#include <boost/typeof/std/functional.hpp>
BOOST_AUTO(fun, std::bind2nd(std::less<int>(), 21)); //create named function object for future use.
[endsect]
[section:what What needs to be registered?]
It is possible to take advantage of the compiler when registering types for the Typeof Library.
Even though there is currently no direct support for typeof in the language,
the compiler is aware of what the type of an expression is, and gives an error
if it encounters an expression that has not been handled correctly. In the `typeof` context,
this error message will contain clues to what types needs to be registered with the
Typeof Library in order for `BOOST_TYPEOF` to work.
struct X {};
template<typename A,bool B>
struct Y {};
std::pair<X,Y<int,true> > a;
BOOST_AUTO(a,b);
We get the following error message from VC7.1
[pre
error C2504: 'boost::type_of::'anonymous-namespace'::encode_type_impl<V,Type_Not_Registered_With_Typeof_System>' : base
class undefined
with
\[
V=boost::type_of::'anonymous-namespace'::encode_type_impl<boost::mpl::vector0<boost::mpl::na>,std::pair<X,Y<int,true>>>::V0,
Type_Not_Registered_With_Typeof_System=X
\]
]
Inspecting this error message, we see that the compiler complains about `X`
BOOST_TYPEOF_REGISTER_TYPE(X); //register X with the typeof system
Recompiling, we get a new error message from VC7.1
[pre
error C2504: 'boost::type_of::'anonymous-namespace'::encode_type_impl<V,Type_Not_Registered_With_Typeof_System>' : base
class undefined
with
\[
V=boost::type_of::'anonymous-namespace'::encode_type_impl<boost::mpl::vector0<boost::mpl::na>,std::pair<X,Y<int,true>>>::V1,
Type_Not_Registered_With_Typeof_System=Y<int,true>
\]
]
Inspecting this error message, we see that the compiler complains about `Y<int,true>`.
Since `Y` is a template, and contains integral constants, we need to take more care when registering:
BOOST_TYPEOF_REGISTER_TEMPLATE(Y,(typename)(bool)); //register template class Y
It is a good idea to look up the exact definition of `Y` when it contains integral constants.
For simple template classes containing only typenames, you can rely solely on the compiler error.
The above code now compiles.
This technique can be used to get an overview of which types needs to be registered
for a given project in order to support `typeof`.
[endsect]
[section:comp Compilers]
The system has been tested with the following compilers:
* MSVC 6.5/7.0/7.1/8.0;
* GCC 3.4.2
[endsect]
[section:limi Limitations]
Nested template template parameters are not supported, like:
template<template<template<class> class> class Tpl>
class A; // can't register!
Classes and templates nested inside other templates also can't be registered
because of the issue of nondeduced context. This limitation is most noticeable
with regards to standard iterators in Dinkumware STL, which are implemented
as nested classes. Instead, instantiations can be registered:
BOOST_TYPEOF_REGISTER_TYPE(std::list<int>::const_iterator)
[endsect]
[endsect]
[section:cont Contributed By:]
* Compliant compilers -- Arkadiy Vertleyb, Peder Holt
* MSVC 6.5, 7.0, 7.1 -- Igor Chesnokov, Peder Holt
[endsect]
[section:ackn Acknoledgements]
The idea of representing a type as multiple compile-time integers,
and passing these integers across function boundaries using sizeof(),
was taken from Steve Dewhurst's article "A Bitwise typeof Operator", CUJ 2002.
This article can also be viewed online, at [@http://www.semantics.org/localarchive.html
http://www.semantics.org/localarchive.html].
Special thank you to Paul Mensonides, Vesa Karvonen, and Aleksey Gurtovoy
for the Boost Preprocessor Library and MPL. Without these two libraries,
this typeof implementation would not exist.
The following people provided support, gave valuable comments,
or in any other way contributed to the library development
(in alphabetical order):
* David Abrahams
* Andrey Beliakov
* Joel de Guzman
* Daniel James
* Vesa Karvonen
* Paul Mensonides
* Alexander Nasonov
* Martin Wille
[endsect]

View File

@ -25,8 +25,8 @@ namespace boost{namespace type_of{namespace{
template<class Iter>
struct decode_type : decode_type_impl<
typename mpl::deref<Iter>::type,
typename mpl::next<Iter>::type
typename Iter::type,
typename Iter::next
>
{};
}}}

View File

@ -28,7 +28,7 @@
#define BOOST_TYPEOF_ENCODE_PARAMS(n, ID) \
BOOST_PP_REPEAT(n, BOOST_TYPEOF_ENCODE_PARAMS_BEGIN, ~) \
typename mpl::push_back<V, mpl::size_t<ID> >::type \
typename push_back<V, mpl::size_t<ID> >::type \
BOOST_PP_REPEAT(n, BOOST_TYPEOF_ENCODE_PARAMS_END, ~)
#endif//BOOST_TYPEOF_ENCODE_DECODE_PARAMS_HPP_INCLUDED

View File

@ -53,14 +53,14 @@ namespace boost{namespace type_of{
////////////////////////////////
template<class V, size_t n, bool overflow = (n >= 0x3fffffff)>
struct encode_size_t : mpl::push_back<
struct encode_size_t : push_back<
V,
boost::mpl::size_t<pack<n, false>::value>
>
{};
template<class V, size_t n>
struct encode_size_t<V, n, true> : mpl::push_back<typename mpl::push_back<
struct encode_size_t<V, n, true> : push_back<typename push_back<
V,
boost::mpl::size_t<pack<n % 0x3ffffffe, true>::value> >::type,
boost::mpl::size_t<n / 0x3ffffffe>
@ -86,22 +86,22 @@ namespace boost{namespace type_of{
template<size_t n, class Iter>
struct decode_size_t<n, Iter, true>
{
enum {m = boost::mpl::deref<Iter>::type::value};
enum {m = Iter::type::value};
enum {value = (size_t)m * 0x3ffffffe + n};
typedef typename boost::mpl::next<Iter>::type iter;
typedef typename Iter::next iter;
};
template<class T, class Iter>
struct decode_integral
{
enum {m = boost::mpl::deref<Iter>::type::value};
enum {m = Iter::type::value};
enum {n = unpack<m>::value};
enum {overflow = unpack<m>::overflow};
typedef typename boost::mpl::next<Iter>::type nextpos;
typedef typename Iter::next nextpos;
static const T value = (T)(size_t)decode_size_t<n, nextpos, overflow>::value;

View File

@ -16,7 +16,7 @@
{\
typedef\
typename encode_type<\
typename mpl::push_back<\
typename push_back<\
V\
, mpl::size_t<ID> >::type\
, T>::type\
@ -60,8 +60,8 @@ namespace boost{namespace type_of{namespace{
{\
typedef\
typename encode_type<\
typename mpl::push_back<\
typename mpl::push_back<\
typename push_back<\
typename push_back<\
V\
, mpl::size_t<ID> >::type\
, mpl::size_t<N> >::type\
@ -71,8 +71,8 @@ namespace boost{namespace type_of{namespace{
template<class Iter>\
struct decode_type_impl<mpl::size_t<ID>, Iter>\
{\
enum{n = mpl::deref<Iter>::type::value};\
typedef decode_type<typename mpl::next<Iter>::type> d;\
enum{n = Iter::type::value};\
typedef decode_type<typename Iter::next> d;\
typedef typename d::type Qualifier type[n];\
typedef typename d::iter iter;\
}

View File

@ -131,7 +131,7 @@
>\
struct encode_type_impl<V, Name<BOOST_PP_ENUM_PARAMS(Size, P)> >\
{\
typedef typename mpl::push_back<V, boost::mpl::size_t<ID> >::type V0;\
typedef typename push_back<V, boost::mpl::size_t<ID> >::type V0;\
BOOST_PP_SEQ_FOR_EACH_I(BOOST_TYPEOF_REGISTER_TEMPLATE_ENCODE_PARAM, ~, Params)\
typedef BOOST_PP_CAT(V, Size) type;\
};\

View File

@ -65,7 +65,7 @@ namespace boost
{};
template<class Iter> struct decode_template
: decode_template_impl<typename mpl::deref<Iter>::type, typename mpl::next<Iter>::type>
: decode_template_impl<typename Iter::type, typename Iter::next>
{};
}
}
@ -82,7 +82,7 @@ namespace boost
BOOST_PP_ENUM_PARAMS(\
BOOST_PP_SEQ_SIZE(Params),\
P)> >\
: mpl::push_back<V, mpl::size_t<ID> >\
: push_back<V, mpl::size_t<ID> >\
{\
};\
template<class Iter> struct decode_template_impl<mpl::size_t<ID>, Iter>\

View File

@ -8,7 +8,7 @@
#define BOOST_TYPEOF_REGISTER_TYPE_IMPL(T, Id) \
\
template<class V> struct encode_type_impl<V, T > \
: mpl::push_back<V, mpl::size_t<Id> > \
: push_back<V, mpl::size_t<Id> > \
{}; \
template<class Iter> struct decode_type_impl<mpl::size_t<Id>, Iter> \
{ \

View File

@ -1,4 +1,5 @@
// Copyright (C) 2004 Arkadiy Vertleyb
// Copyright (C) 2004, 2005 Arkadiy Vertleyb
// Copyright (C) 2005 Peder Holt
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (http://www.boost.org/LICENSE_1_0.txt)
@ -8,73 +9,46 @@
#include <boost/mpl/size_t.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/typeof/encode_decode.hpp>
#include <boost/typeof/vector.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/begin_end.hpp>
#include <boost/mpl/push_back.hpp>
#define BOOST_TYPEOF_VECTOR(n) BOOST_PP_CAT(boost::type_of::vector, n)
#ifdef BOOST_TYPEOF_USE_MPL_VECTOR
# include <boost/mpl/vector.hpp>
# include <boost/typeof/limit_size.hpp>
# define BOOST_TYPEOF_VECTOR(n) BOOST_PP_CAT(boost::mpl::vector, n)
#else
# include <boost/typeof/vector.hpp>
# define BOOST_TYPEOF_VECTOR(n) BOOST_PP_CAT(boost::type_of::vector, n)
#endif
#define BOOST_TYPEOF_sizer_item(z, n, _)\
char item ## n[V::item ## n ::value];
namespace boost{namespace type_of{
template<int pos, class T>
struct at_result
{
typedef typename encode_type<BOOST_TYPEOF_VECTOR(0)<>, T>::type encoded_type;
typedef typename mpl::size<encoded_type>::type size;
typedef char(&type)[
mpl::at<
encoded_type,
mpl::int_<(pos < size::value) ? pos : 0>
>::type::value
];
};
namespace boost { namespace type_of {
template<int pos, class T>
typename at_result<pos, T>::type at(const T&);
template<class V>
struct sizer
{
// char item0[V::item0::value];
// char item1[V::item1::value];
// ...
template<class T>
char(&size(const T&))[
mpl::size<typename encode_type<BOOST_TYPEOF_VECTOR(0)<>, T>::type>::value
];
BOOST_PP_REPEAT(BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_sizer_item, ~)
};
template<class T>
sizer<typename encode_type<BOOST_TYPEOF_VECTOR(0)<>, T>::type> encode(const T&);
}}
#define BOOST_TYPEOF_AT(n, expr) sizeof(boost::type_of::at<n>(expr))
#define BOOST_TYPEOF_SIZE(expr) sizeof(boost::type_of::size(expr))
#undef BOOST_TYPEOF_sizer_item
#ifndef BOOST_TYPEOF_NO_SIMPLE_TYPE_OPTIMIZATION
# define BOOST_TYPEOF_TYPEITEM(z, n, expr)\
boost::mpl::size_t<BOOST_TYPEOF_AT((n < BOOST_TYPEOF_SIZE(expr)) ? n : 0, expr)>
#else
# define BOOST_TYPEOF_TYPEITEM(z, n, expr)\
boost::mpl::size_t<BOOST_TYPEOF_AT(n, expr)>
#endif
#define BOOST_TYPEOF_TYPEITEM(z, n, expr)\
boost::mpl::size_t<sizeof(boost::type_of::encode(expr).item ## n)>
#define BOOST_TYPEOF(Expr) \
boost::type_of::decode_type< \
boost::mpl::begin< \
BOOST_TYPEOF_VECTOR(BOOST_TYPEOF_LIMIT_SIZE)< \
BOOST_PP_ENUM(BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_TYPEITEM, Expr) \
> \
>::type \
#define BOOST_TYPEOF(Expr) \
boost::type_of::decode_type< \
BOOST_TYPEOF_VECTOR(BOOST_TYPEOF_LIMIT_SIZE)< \
BOOST_PP_ENUM(BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_TYPEITEM, Expr) \
>::begin \
>::type
#define BOOST_TYPEOF_TPL(Expr) \
typename boost::type_of::decode_type< \
typename boost::mpl::begin< \
BOOST_TYPEOF_VECTOR(BOOST_TYPEOF_LIMIT_SIZE)< \
BOOST_PP_ENUM(BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_TYPEITEM, Expr) \
> \
>::type \
#define BOOST_TYPEOF_TPL(Expr) \
typename boost::type_of::decode_type< \
typename BOOST_TYPEOF_VECTOR(BOOST_TYPEOF_LIMIT_SIZE)< \
BOOST_PP_ENUM(BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_TYPEITEM, Expr) \
>::begin \
>::type
#endif//BOOST_TYPEOF_COMPLIANT_TYPEOF_IMPL_HPP_INCLUDED

View File

@ -1,22 +1,15 @@
// Copyright (C) 2005 Arkadiy Vertleyb
// Copyright (C) 2005 Peder Holt
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (http://www.boost.org/LICENSE_1_0.txt)
// Minimal replacement for mpl::vector<>.
// Works a little faster with VC7.1 and a lot faster with GCC (compliant mode).
// Define BOOST_TYPEOF_USE_MPL_VECTOR to avoid it and use mpl::vector<> instead.
#ifndef BOOST_TYPEOF_VECTOR_HPP_INCLUDED
#define BOOST_TYPEOF_VECTOR_HPP_INCLUDED
#include <boost/mpl/at.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/mpl/next.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/int.hpp>
#include <boost/preprocessor/enum_params.hpp>
#include <boost/preprocessor/repeat.hpp>
#include <boost/preprocessor/repeat_from_to.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/inc.hpp>
#include <boost/preprocessor/comma_if.hpp>
@ -27,87 +20,49 @@
// iterator
namespace boost{namespace type_of{
template<class V, class Pos>
struct v_iter
{
typedef typename boost::mpl::at<V, Pos>::type type;
typedef v_iter<V, typename boost::mpl::next<Pos>::type> next;
#define BOOST_TYPEOF_spec_iter(z, n, _)\
template<class V>\
struct v_iter<V, mpl::int_<n> >\
{\
typedef typename V::item ## n type;\
typedef v_iter<V, mpl::int_<n + 1> > next;\
};
namespace boost{ namespace type_of{
template<class V, class Pos> struct v_iter; // not defined
BOOST_PP_REPEAT(BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_spec_iter, ~)
}}
#undef BOOST_TYPEOF_spec_iter
// vector
#define BOOST_TYPEOF_typedef_item(z, n, _)\
typedef P ## n item ## n;
#define BOOST_TYPEOF_typedef_fake_item(z, n, _)\
typedef mpl::int_<1> item ## n;
#define BOOST_TYPEOF_define_vector(z, n, _)\
template<BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_COMMA_IF(n) class T = void>\
struct vector ## n\
{\
typedef v_tag tag;\
typedef v_iter<vector ## n, boost::mpl::int_<0> > begin;\
typedef mpl::int_<n> size;\
BOOST_PP_REPEAT(n, BOOST_TYPEOF_typedef_item, ~)\
BOOST_PP_REPEAT_FROM_TO(n, BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_typedef_fake_item, ~)\
};
namespace boost{namespace type_of{
class v_tag;
namespace boost{ namespace type_of{
BOOST_PP_REPEAT(BOOST_PP_INC(BOOST_TYPEOF_LIMIT_SIZE), BOOST_TYPEOF_define_vector, ~)
}}
#undef BOOST_TYPEOF_typedef_item
#undef BOOST_TYPEOF_typedef_fake_item
#undef BOOST_TYPEOF_define_vector
// at (specializing at rather than at_impl gives some performance gain)
#define BOOST_TYPEOF_spec_at(z, n, _)\
template<class V>\
struct at<V, int_<n> >\
{\
typedef typename V::item ## n type;\
};
namespace boost{namespace mpl{
BOOST_PP_REPEAT(BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_spec_at, ~)
}}
/*
#define BOOST_TYPEOF_spec_at(z, n, _)\
template<class V>\
struct apply<V, int_<n> >\
{\
typedef typename V::item ## n type;\
};
namespace boost{namespace mpl{
template<>
struct at_impl<boost::type_of::v_tag>
{
template<class V, class N>
struct apply;
BOOST_PP_REPEAT(BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_spec_at, ~)
};
}}
*/
#undef BOOST_TYPEOF_spec_at
// size
namespace boost{namespace mpl{
template<>
struct size_impl<boost::type_of::v_tag>
{
template<class V>
struct apply
{
typedef typename V::size type;
};
};
}}
// push_back (specializing push_back rather than push_back_impl gives some performance gain)
// push_back
#define BOOST_TYPEOF_spec_push_back(z, n, _)\
template<BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_COMMA_IF(n) class T>\
@ -118,31 +73,12 @@ namespace boost{namespace mpl{
> type;\
};
namespace boost{namespace mpl{
namespace boost{ namespace type_of{
template<class V, class T> struct push_back; // not defined
BOOST_PP_REPEAT(BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_spec_push_back, ~)
}}
/*
#define BOOST_TYPEOF_spec_push_back(z, n, _)\
template<BOOST_PP_ENUM_PARAMS(n, class P) BOOST_PP_COMMA_IF(n) class T>\
struct apply<BOOST_PP_CAT(boost::type_of::vector, n)<BOOST_PP_ENUM_PARAMS(n, P)>, T>\
{\
typedef BOOST_PP_CAT(boost::type_of::vector, BOOST_PP_INC(n))<\
BOOST_PP_ENUM_PARAMS(n, P) BOOST_PP_COMMA_IF(n) T\
> type;\
};
namespace boost{namespace mpl{
template<>
struct push_back_impl<boost::type_of::v_tag>
{
template<class V, class T>
struct apply;
BOOST_PP_REPEAT(BOOST_TYPEOF_LIMIT_SIZE, BOOST_TYPEOF_spec_push_back, ~)
};
}}
*/
#undef BOOST_TYPEOF_spec_push_back
#endif//BOOST_TYPEOF_COMPLIANT_VECTOR_HPP_INCLUDED

View File

@ -324,6 +324,9 @@
RelativePath="..\mpl\register.hpp">
</File>
</Filter>
<File
RelativePath="..\..\doc\typeof.qbk">
</File>
</Files>
<Globals>
</Globals>