123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884 |
- [library Boost.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>)
- ]
- [id typeof]
- [last-revision $Date$]
- ]
- [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 template parameters, as well as parameters to the constructor:
- 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 complex 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 (as well as some other problems),
- the C++ standard committee is considering
- a few additions to the standard language, such as `typeof/decltype` and `auto` (see
- [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1607.pdf
- http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1607.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;
- The purpose of the Boost.Typeof library is to provide a library-based solution,
- which could be used until the language-based facility is added to the Standard
- and becomes widely available.
-
- [endsect]
- [section:tuto Tutorial]
- To start using typeof include the typeof header:
- #include <boost/typeof/typeof.hpp>
- 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 for example a reference, it has to be specified 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 has to
- 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 must 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 variable to be initialized with the expression]]
- [[expr][a valid c++ expression]]
- ]
- [h4 Remarks]
- If you want to use `auto` in a template-context, use `BOOST_AUTO_TPL(expr)`,
- which takes care of the `typename` keyword inside the `auto` expression.
- [h4 Sample Code]
- int 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.)
- Other non-type template parameters (e.g. pointer to member)
- are not supported.
- [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:messages MESSAGES]
- Define `BOOST_TYPEOF_MESSAGE` before including boost/typeof/typeof.hpp to
- include messages "using typeof emulation" and "using native typeof".
- By default, these messages will not be displayed.
- [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: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`
- * Enums and typedefs of integral types, 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 can be bound to const T&]]
- ]
- [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]
- [section:typn TYPEOF_NESTED_TYPEDEF, TYPEOF_NESTED_TYPEDEF_TPL]
- The `TYPEOF_NESTED_TYPEDEF` macro works in much the same way as the 'TYPEOF' macro does, but
- workarounds several compiler deficiencies.
- [h4 Usage]
- BOOST_TYPEOF_NESTED_TYPEDEF(name,expr)
- BOOST_TYPEOF_NESTED_TYPEDEF_TPL(name,expr)
-
- [variablelist Arguments
- [[name][a valid identifier to nest the typeof operation inside]
- [expr][a valid c++ expression that can be bound to const T&]]
- ]
- [h4 Remarks]
- 'typeof_nested_typedef' nests the 'typeof' operation inside a struct. By doing this, the 'typeof' operation
- can be split into two steps, deconfusing several compilers (notably VC7.1 and VC8.0) on the way.
- This also removes the limitation imposed by `BOOST_TYPEOF_LIMIT_SIZE` and allows you to use 'typeof' on much
- larger expressions.
- If you want to use `typeof_nested_typedef` in a template-context, use `BOOST_TYPEOF_NESTED_TYPEDEF_TPL(name,expr)`,
- which takes care of `typename` inside the `typeof` expression.
- 'typeof_nested_typedef' can not be used at function/block scope.
- [h4 Sample Code]
- template<typename A, typename B>
- struct result_of_conditional
- {
- BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested,true?A():B())
- typedef typename nested::type 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 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;
-
- Peder Holt adapted this method to VC7.0, where the nested class
- is a template class that is specialized in the derived class.
- In VC8.0, it seemed that all the bug-featire had been fixed, but
- Steven Watanabe managed to implement a more rigorous version of the VC7.0 fix that
- enables 'typeof' to be supported 'natively' here as well.
-
- For 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: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 Acknowledgements]
- 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
- * Andy Little
- * Paul Mensonides
- * Alexander Nasonov
- * Tobias Schwinger
- * Martin Wille
- [endsect]
|