diff --git a/.travis.yml b/.travis.yml index f9c23d05..26f0c56d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -83,7 +83,7 @@ install: - | if [[ "${BUILD_DOC}" == "true" ]] then - DOXYGEN_URL="http://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.10.linux.bin.tar.gz" + DOXYGEN_URL="http://ftp.stack.nl/pub/users/dimitri/doxygen-1.8.11.linux.bin.tar.gz" mkdir "${DEPS_PATH}/doxygen" && travis_retry wget --quiet -O - ${DOXYGEN_URL} | tar --strip-components=1 -xz -C "${DEPS_PATH}/doxygen" && export PATH=${DEPS_PATH}/doxygen/bin:${PATH} diff --git a/CMakeLists.txt b/CMakeLists.txt index 45e03be8..ad64ea27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,10 +94,6 @@ endif() if(METAL_ENABLE_EXTRA_WARNINGS) metal_add_flag(-Wextra) - metal_add_flag(-Weverything) - metal_add_flag(-Wno-c++98-compat) - metal_add_flag(-Wno-c++98-compat-pedantic) - metal_add_flag(-Wno-documentation-unknown-command) metal_add_flag(/W4) endif() @@ -107,8 +103,6 @@ if(METAL_STRICT) metal_add_flag(/WX) endif() -metal_add_flag(-ftemplate-depth=512) - foreach(dialect -std=c++17 -std=c++1z -std=c++14 -std=c++1y diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index d4a3682a..5d4a6602 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -228,6 +228,8 @@ TAB_SIZE = 4 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. +ALIASES += strike{1}="
\1
" + ALIASES +=value="\ref concepts_value" ALIASES +=values="\ref concepts_value \"Values\"" ALIASES +=optional="\ref concepts_optional" diff --git a/doc/css/metal.css b/doc/css/metal.css index 7916ddeb..14b35637 100644 --- a/doc/css/metal.css +++ b/doc/css/metal.css @@ -129,6 +129,10 @@ span.octicon { margin-right: 5px; } +.strike { + text-decoration: line-through; +} + #footer { height: 100px; font-size: 0.9em; diff --git a/doc/manual.md b/doc/manual.md index de7a992c..04e8d05f 100644 --- a/doc/manual.md +++ b/doc/manual.md @@ -2,23 +2,11 @@ \tableofcontents -Metal is a general-purpose, header-only [C++11][C++11] -[template metaprogramming][tmp] library designed to make -metaprogramming enjoyable. -It provides a powerful high-level abstraction for compile-time algorithms, -grounded on a concise yet solid [conceptual foundation](\ref concepts). - -With focus on [simplicity] and [expressiveness], -Metal explores the full potential of modern features, without, -on the other hand, -allowing its [portability](\ref portability) to be compromised. -Metal does its best to follow the -[principle of least astonishment][pola], -mimicking well established concepts used by the [STL], much like its ancestor -and main source of inspiration, the [Boost.MPL]. -In fact, Metal was born *MPL2*, an independent attempt to modernize Boost.MPL, -but soon it became clear that it was something more than just a remake, -so thus became **Metal** - Metaprogramming Algorithms. +Metal is a [portable](\ref portability) header-only [C++11] library +designed to make [template metaprogramming][tmp] enjoyable. +To that end, it provides a powerful high-level [abstraction](\ref concepts) for +compile-time algorithms that mimic the [standard algorithms library][algorithm], +hence **Metal** - Metaprogramming Algorithms. Motivation {#motivation} ================================================================================ @@ -39,16 +27,16 @@ by Aleksey Gurtovoy and David Abrahams, is officially shipped with Boost version 1.30.0. A masterpiece of template metaprogramming, it went to great lengths to support the -widest variety of poorly conforming if not utterly defective compilers, +widest variety of poorly conforming compilers, abstracting away the nastiest compiler hackery to present a uniform -framework that finally could be relied upon. -It played a crucial role in the dissemination of metaprogramming in C++ and -remained undisputed for almost a decade, -but, eventually, it started showing its age when [C++11] introduced, +framework that finally could be relied upon, +thus playing a crucial role in the dissemination of metaprogramming in C++. +The Boost.MPL remained undisputed for almost a decade, but +eventually, it started showing its age when [C++11] introduced, among various others, [variadic templates][variadics], [alias templates], [type inference][decltype] and [constant expressions][constexpr] to the core language. -This powerful C++11 machinery enabled the development of whole new +The powerful C++11 machinery enabled the development of whole new metaprogramming [styles][tmp.simple] and [techniques][tmp.modern] with potential to outperform Boost.MPL by orders of magnitude in many instances. Moreover, the need for endless automatically generated boilerplate code could @@ -56,7 +44,7 @@ finally be overcome using variadic templates, whereas syntax clutter could be mitigated using alias templates, vastly improving readability. -Eventually, [motivation][mpl.lite] to modernize Boost.MPL emerged from the +Eventually, [motivation][mpl.lite] to modernize Boost.MPL emerged from the Boost community, even though opinions diverged widely on the matter. As diverse has been the development of new metaprogramming libraries with varying degrees of success, @@ -65,8 +53,8 @@ Louis Dionne, the latter formally accepted into the Boost distribution in July 2015. Metal is yet another approach to modern C++11 metaprogramming. -Its ultimate goal is to be regarded as the best alternative to Boost.MPL in -every use case where support for C++11 is desired, +Its ultimate goal is to be regarded as the natural successor of Boost.MPL in +every use case where C++11 is available, delivering greater performance and expressiveness without cluttering the codebase. Although not a perfect drop in replacement for Boost.MPL, @@ -79,7 +67,7 @@ Getting Started {#getting_started} It's very easy to start enjoying metaprogramming with Metal, being header-only with no external dependencies, -all you have to do is download and optionally install it system-wide. +all you have to do is download it. Downloading {#downloading} -------------------------------------------------------------------------------- @@ -93,7 +81,7 @@ you can clone current stable branch `master` from GitHub. git clone https://github.com/brunocodutra/metal -Likewise, the [bleeding edge] development version can be obtained by cloning +Likewise, the bleeding edge development version can be obtained by cloning branch `develop` instead. git clone https://github.com/brunocodutra/metal --branch=develop @@ -124,14 +112,14 @@ From within an empty directory issue the following commands. Unless otherwise specified, Metal's include tree will be copied into the default prefix for locally installed libraries in your platform, -that is `/usr/local/include` on [Unix[-like]][unix-like] systems and +that is `/usr/local/include` on Unix[-like] systems and `C:\Program Files\Metal\include` on Windows. Simply add the installation prefix to the include search path of your -compiler/project if it hasn't been already, and you're good to go. +compiler/project if it isn't by default, and you're good to go. If your project uses [CMake], Metal may also be integrated into your project via `find_package`, -whereupon `METAL_INCLUDE_DIRS` will be set to contain +whereupon `METAL_INCLUDE_DIRS` is set to contain all necessary include prefixes. In short, simply add the following to the `CMakeLists.txt` of your project. @@ -143,7 +131,7 @@ For more information, please refer to [CMake documentation][CMake.doc]. Documentation {#documentation} -------------------------------------------------------------------------------- -An offline copy of this documentation website may be obtained by cloning +An offline copy of this documentation may be obtained by cloning branch `gh-pages`. git clone https://github.com/brunocodutra/metal --branch=gh-pages @@ -158,7 +146,7 @@ From within an empty directory issue the following commands. The documentation will be generated into `doc/html/`. To browse the documentation offline, -simply load `index.html` on your favorite web browser. +simply load `index.html` on any web browser that supports [JavaScript]. Portability {#portability} ================================================================================ @@ -166,8 +154,7 @@ Portability {#portability} Great effort is undertaken to keep Metal strictly in conformance with the C++11 standard and compatible with the widest possible variety of compilers. To this end, some of the most popular freely available C++ compilers are -officially and actively supported through [Continuous Integration (CI)][ci] -premisses. +actively supported through [Continuous Integration (CI)][ci] premisses. GCC and Clang are tested with help of [Travis CI][travis.metal], while Microsoft Visual Studio is tested using [Appveyor CI][appveyor.metal]. @@ -265,7 +252,7 @@ specialization of [std::integral_constant][integral]. ### See Also -metal::number, metal::boolean, metal::integer +metal::number, metal::boolean, metal::integer, metal::character Optional {#concepts_optional} -------------------------------------------------------------------------------- @@ -276,7 +263,7 @@ represent either *just* some other [Value] or *nothing*. In order to *evaluate* an [Optional] one must explicitly name its nested `::type`. An [Optional] is said to be empty, -whenever a nested `::type` is undefined or ambiguously defined, +whenever a nested [Value] called `::type` is undefined or ambiguously defined, thus attempting to *evaluate* an empty [Optional] leads to a compile-time error. \tip{ @@ -286,7 +273,7 @@ for any [Optional] `opt`. ### Requirements -Any type is an [Optional]. +Any [Value] is also an [Optional]. ### Examples @@ -313,16 +300,16 @@ In general, however, an [Expression] may be *empty* for some set of arguments, thus attempting to *evaluate* such an [Expression] for such set of arguments leads to a compile-time error. -\note{ -Because [Expressions] are not themselves [Values], -it is not possible to write [higher-order] expressions. -} - ### Requirements `expr` is a model of [Expression] if and only if `expr` is a template class, union or alias that only expects types as arguments. +\note{ +Because [Expressions] are not themselves [Values], +it is not possible to define [higher-order] expressions directly. +} + ### Examples \snippet concepts/expression.cpp ex1 @@ -349,20 +336,20 @@ the [Lambda Calculus]. ### Requirements -Any type is a [Lambda]. +Any [Value] is also a [Lambda]. ### Semantics Let `expr` be an [Expression], `[a1, ..., ai, ..., an]` atomic [Values], `[_1, ..., _i, ..., _n]` [Placeholders] and `[l1, ..., li, ..., ln]` [Lambdas]. -* Invoking `ai` for any (possibly empty) set of [Values] yields `ai` -* Invoking `_i` for `[a1, ..., ai, ..., an]` yields `ai` -* Invoking `metal::lambda` for `[a1, ..., an]` yields +* Invoking `ai` with any (possibly empty) set of [Values] yields `ai` +* Invoking `_i` with `[a1, ..., ai, ..., an]` yields `ai` +* Invoking `metal::lambda` with `[a1, ..., an]` yields `expr::type` -* Invoking `expr` for `[a1, ..., an]` -invokes `metal::lambda` for the set of [Values] yielded by -invoking each `li` for `[l1, ..., ln]`. +* Invoking `expr` with `[a1, ..., an]` +invokes `metal::lambda` with the [Values] yielded by +recursively invoking each `li` with `[a1, ..., an]`. \tip{ `metal::lambda` can be used to adapt any [Expression] `expr` @@ -388,7 +375,7 @@ A [List] is a sequence of [Values]. ### Requirements -A [List] is any specialization of any template class or union, +A [List] is any specialization of any template class or union that only expects types as arguments. ### Examples @@ -436,7 +423,7 @@ each of which is associated with another [Value]. A [Map] is a [List] of [Pairs], whose first elements are all distinct, that is - [[k0, v0], ..., [kn, vn]]; ki != kj for all i, j in {0, n} + [[k0, v0], ..., [kn, vn]]; ki != kj for all i, j in {0, n} and i != j ### Examples @@ -456,25 +443,32 @@ Data-Code Duality {#concepts_duality} ================================================================================ Markedly influenced by various functional programming languages, -such as [Haskell] and [SML], Metal owes much of its design to [Lisp] -in particular. +such as [Haskell] and [SML], +Metal owes much of its design particularly to [Lisp]. From it, Metal borrowed [s-expressions] and the notion that data structures and algorithms are nothing -but [two sides of the same coin][homoiconicity]. +but [two sides of the same coin][homoiconicity], that is, +Metal makes no difference between lists and unevaluated expressions. + +Take for instance the following definition. + +\snippet manual/homoiconicity.cpp 1 + +Here `sum` could be understood as an unevaluated addition of three numbers, thus -Much like Lisp, Metal makes no difference between lists and unevaluated -expressions. -The following, for example, could be seen as an unevaluated expression -that represents the sum of two numbers. +\snippet manual/homoiconicity.cpp 2 -\snippet manual.cpp sum +Alternativelly, `sum` could also be seen as a [List] that contains three values -Just as accurately, it could also be seen as a pair. +\snippet manual/homoiconicity.cpp 3 -\snippet manual.cpp first -\snippet manual.cpp second +Now, just like any [List], `sum` may be transformed into a new [List] -Now that may look silly put in a simple example like this one, but [...] +\snippet manual/homoiconicity.cpp 4 + +... which in turn may be seen as the sum of the squares of the same three numbers. + +\snippet manual/homoiconicity.cpp 5 \tip{ To save typing, most [Expressions] in Metal have an associated eager adaptor @@ -483,6 +477,200 @@ given an expression `metal::expr`, `metal::expr_t<...>` is equivalent to `typename metal::expr<...>::type`. } +Metal in Action {#metal_in_action} +================================================================================ + +Enough theory, lets see some action! + +Parsing Raw Literals {#parsing_raw_literals} +-------------------------------------------------------------------------------- + +If you ever considered augmenting [`std::tuple`][tuple], +so that instead of the rather odd [`std::get()`][get] + +\snippet tutorial/literal.cpp teaser_1 + +one could just use the more intuitive subscript operator `[N]`, + +\strike{ +\snippet tutorial/literal.cpp teaser_2 +} + +chances are you realized the hard way +that the reason why such an operator is not overloaded by default is because +there's simply no way of overloading such an operator! + +All is not lost however if you can live with the subscript operator taking an +object of type `std::integral_constant`, or in Metal's parlance [Number], +instead of an usual integral value. + +\snippet tutorial/literal.cpp super_tuple + +\snippet tutorial/literal.cpp teaser_3 + +Neat isn't it? +Now we need a [literal operator][literal] `_c` that encodes an integral value +as a [Number]. Sounds simple enough, right? + +\strike{ +\snippet tutorial/literal.cpp naive +} + +Not really. While `constexpr` tells the compiler the value returned by +`operator ""_c` might be a compile time constant, +it tells no such thing about its argument. +We are thus left no other option but to parse raw literals ourselves, +in other words, we are in for some fun! + +### The Raw Literal Operator Template + +Raw literal operator templates are defined as a nullary function templated over +`char...`, such as + +\snippet tutorial/literal.cpp raw + +where `tokens...` are mapped to the exact characters that make up the literal, +including the prefixes `0x` and `0b` + +\snippet tutorial/literal.cpp raw_examples_1 + +as well as the digit separator `'` introduced by [C++14] + +\snippet tutorial/literal.cpp raw_examples_2 + +### The `operator ""_c` + +We start by defining our very own literal operator `_c`. +It simply wraps each token into a `metal::character` and forwards them to an +[Expression] that effectively parses the [Number], we'll call it, +suggestively, `make_number`. + +\snippet tutorial/literal.cpp _c + +### Resolving the Radix + +In its turn `make_number` strips the prefix, if any, thus resolving the radix, +then forwards the remaining tokens to `parse_digits`, +which is in charge of translating the raw characters to a [List] of +integral [Numbers]. +The radix and digits are then forwarded to `compute`, which adds up the digits +according to the radix. + +\snippet tutorial/literal.cpp make_number + +Notice that we followed the notation used by Metal and defined `make_number_t` +as an alias to `typename make_number<>::type` to save typing. + +### Parsing the Digits + +To parse the characters into the corresponding integral, we need first to remove +all digit separators. +That can be easily accomplished using `metal::remove`, which takes a [List] `l` +and a [Value] `v` and returns another [List] that contains every element from +`l` and in the same order, except for those that are identical to `v`. + +\snippet tutorial/literal.cpp remove + +The remaining digits can then be transformed into the corresponding +[Numbers] using `metal::transform`, which takes a [Lambda] `lbd` and a +[List] `l` and returns another [List] containing the results of *invoking* `lbd` +for each element in `l`. + + [lbd(l[0]), lbd(l[1]), ..., lbd(l[n-2]), lbd(l[n-1])] + +First we need an [Expression] that maps characters to +[Numbers] from which we can construct our `lbd`. +We'll call it `to_number` and it is rather trivial. + +\snippet tutorial/literal.cpp to_number + +Now we can transform characters to [Numbers]. + +\snippet tutorial/literal.cpp transform_1 + +That peculiar `metal::_1` is a placeholder and it works like this: +when `to_number` is invoked with some argument, +`metal::_1` will be substituted for that argument and only then `to_number` +is *evaluated*. + +Putting it all together we have + +\snippet tutorial/literal.cpp parse_digits + +### Computing the Number + +Now we turn our attention to `compute`. +It takes the radix and a list of [Numbers] representing the digits and is in +charge of adding up the digits according to the radix, that is + + D0*radix^(n-1) + D1*radix^(n-2) + ... + D{n-2}*radix + D{n-1} + +The first thing we notice is that the *ith* digit actually corresponds to the +(n-1-i)th power of the radix, so, to make things simpler, +we need to `metal::reverse` the order of digits. + +\snippet tutorial/literal.cpp reverse + +Then we have + + D0 + D1*radix + ... + D{n-2}*radix^(n-2) + D{n-1}*radix^(n-1) + +Now we need to `metal::enumerate` the exponents that correspond to each digit. + +\snippet tutorial/literal.cpp enumerate + +This version of `metal::enumerate` takes two [Numbers], `start` and `size`, +and returns a [List] containing a sequence of [Numbers] beginning with `start` +and ending in `size - 1`. + + [start, start + 1, ..., size - 2, size - 1] + +\note{ +All [Numbers] in the sequence have the same type as `start` +regardless of the type of `size`. +} + +The next step is to compute each term of the sum. +We'll be using `metal::transform` again, but this time it takes a *binary* +[Lambda] `lbd` and two [Lists] `l1` and `l2` and returns a new [List] formed by +*invoking* `lbd` for the elements of `l1` and `l2` pairwise. + + [lbd(l1[0], l2[0]), lbd(l1[1], l2[1]), ..., lbd(l1[n-2], l2[n-2]), lbd(l1[n-1], l2[n-1])] + +\snippet tutorial/literal.cpp transform_2 + +Here again `metal::_1` and `metal::_2` are placeholders that get substituted for +the first and second arguments with which `lbd` is invoked, +prior to the recursive *evaluation* of the [Expressions] that form the [Lambda]. + +Finally we need to sum up the terms, so basically we need to invoke `metal::add` +for the elements contained in a [List]. +That's exactly what `metal::apply` is for. + +\snippet tutorial/literal.cpp sum + +Here we used `metal::lambda` which is basically a synonym for +`metal::add, metal::arg>`, +where `n` is the number of arguments with which `metal::lambda` is +invoked, that is the size of the [List] in this particular case. +This way we don't need to care about the actual number of arguments. + +We now have all the pieces needed to define `compute`. + +\snippet tutorial/literal.cpp compute + +And we are done. + +\snippet tutorial/literal.cpp test_1 + +It even works for very long binary literals. + +\snippet tutorial/literal.cpp test_2 + +And also ignores digit separators. + +\snippet tutorial/literal.cpp test_3 + [Value]: \ref concepts_value [Values]: \ref concepts_value [Optional]: \ref concepts_optional @@ -502,30 +690,30 @@ given an expression `metal::expr`, [Placeholders]: \ref placeholders [C++11]: http://en.wikipedia.org/wiki/C%2B%2B11 -[STL]: http://en.wikipedia.org/wiki/Standard_Template_Library -[pola]: http://en.wikipedia.org/wiki/Principle_of_least_astonishment -[simplicity]: http://en.wikipedia.org/wiki/Simplicity#Quotes_about_simplicity -[expressiveness]: http://en.wikipedia.org/wiki/Expressive_power_%28computer_science%29 +[C++14]: http://en.wikipedia.org/wiki/C%2B%2B14 +[JavaScript]: http://en.wikipedia.org/wiki/JavaScript [higher-order]: http://en.wikipedia.org/wiki/Higher-order_lambda [first-class]: http://en.wikipedia.org/wiki/First-class_citizen [Lambda Calculus]: http://en.wikipedia.org/wiki/Lambda_calculus [s-expressions]: http://en.wikipedia.org/wiki/S-expression [homoiconicity]: http://en.wikipedia.org/wiki/Homoiconicity [ci]: http://en.wikipedia.org/wiki/Continuous_integration -[bleeding edge]: http://en.wikipedia.org/wiki/Bleeding_edge_technology -[unix-like]: http://en.wikipedia.org/wiki/Unix-like [tmp]: http://en.wikipedia.org/wiki/Template_metaprogramming [tmp.turing]: http://ubietylab.net/ubigraph/content/Papers/pdf/CppTuring.pdf [tmp.simple]: http://pdimov.com/cpp2/simple_cxx11_metaprogramming.html [tmp.modern]: http://pdimov.com/cpp2/simple_cxx11_metaprogramming_2.html +[algorithm]: http://en.cppreference.com/w/cpp/algorithm [preprocessor]: http://en.wikipedia.org/wiki/C_preprocessor [variadics]: http://en.cppreference.com/w/cpp/language/parameter_pack [alias templates]: http://en.cppreference.com/w/cpp/language/type_alias [decltype]: http://en.cppreference.com/w/cpp/language/decltype [constexpr]: http://en.cppreference.com/w/cpp/language/constexpr [integral]: http://en.cppreference.com/w/cpp/types/integral_constant +[tuple]: http://en.cppreference.com/w/cpp/utility/tuple +[get]: http://en.cppreference.com/w/cpp/utility/tuple/get +[literal]: http://en.cppreference.com/w/cpp/language/user_literal [CMake]: http://cmake.org/ [CMake.doc]: http://cmake.org/documentation/ diff --git a/example/include/example.hpp b/example/include/example.hpp index 4a8d4f9f..c05262b2 100644 --- a/example/include/example.hpp +++ b/example/include/example.hpp @@ -8,7 +8,7 @@ #define CAT_(X, Y) X##Y #define CAT(X, Y) CAT_(X, Y) -#define ANONYMOUS(SCOPE) SCOPE CAT(anonymous, __LINE__) +#define HIDDEN(SCOPE) SCOPE CAT(anonymous, __LINE__) int main() { diff --git a/example/src/concepts/expression.cpp b/example/src/concepts/expression.cpp index f9ab21b9..56ac9f69 100644 --- a/example/src/concepts/expression.cpp +++ b/example/src/concepts/expression.cpp @@ -8,7 +8,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex1] template @@ -21,7 +21,7 @@ union expr static_assert(metal::is_just>::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex2] template @@ -34,7 +34,7 @@ struct expr static_assert(!metal::is_just>::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex3] template //evaluable for array types @@ -46,31 +46,31 @@ static_assert(metal::is_just>::value, ""); static_assert(metal::is_just>::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [nex1] -struct not_an_expr //not a template +struct not_an_expression //not a template { struct type; }; /// [nex1] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [nex2] template class... exprs> //non-type parameter -struct not_an_expr +struct not_an_expression { struct type; }; /// [nex2] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [nex3] template //non-type parameter -using not_an_expr = std::integral_constant; +using not_an_expression = std::integral_constant; /// [nex3] } diff --git a/example/src/concepts/lambda.cpp b/example/src/concepts/lambda.cpp index 4d56da67..adf1e10b 100644 --- a/example/src/concepts/lambda.cpp +++ b/example/src/concepts/lambda.cpp @@ -8,7 +8,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex1] using lbd = void; @@ -17,7 +17,7 @@ using lbd = void; static_assert(std::is_same, void>::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex2] using lbd = metal::_2; @@ -26,7 +26,7 @@ using lbd = metal::_2; static_assert(std::is_same, int>::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex3] using lbd = metal::lambda; @@ -35,7 +35,7 @@ using lbd = metal::lambda; static_assert(std::is_same, void*>::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex4] using lbd = std::add_pointer; @@ -44,7 +44,7 @@ using lbd = std::add_pointer; static_assert(std::is_same, void*>::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex5] using lbd = std::is_convertible>; diff --git a/example/src/concepts/list.cpp b/example/src/concepts/list.cpp index 43a1c0c6..957e4e9d 100644 --- a/example/src/concepts/list.cpp +++ b/example/src/concepts/list.cpp @@ -8,7 +8,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex1] template @@ -21,7 +21,7 @@ static_assert(metal::is_list_t::value, ""); static_assert(metal::size_t::value == 1, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex2] template @@ -34,16 +34,16 @@ static_assert(metal::is_list_t::value, ""); static_assert(metal::size_t::value == 0, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [nex1] -using not_a_list = union{}; // not a template instantiation +using not_a_list = struct{}; // not a template instantiation /// [nex1] static_assert(!metal::is_list_t::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [nex2] template diff --git a/example/src/concepts/map.cpp b/example/src/concepts/map.cpp index f4a8af56..8d31282c 100644 --- a/example/src/concepts/map.cpp +++ b/example/src/concepts/map.cpp @@ -8,7 +8,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex1] template @@ -23,7 +23,7 @@ using map = many, many, couple>; static_assert(metal::is_map_t::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex2] template @@ -35,7 +35,7 @@ using map = many<>; static_assert(metal::is_map_t::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [nex1] template @@ -50,7 +50,7 @@ using not_a_map = many, couple>; // repeated keys static_assert(!metal::is_map_t::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [nex2] template diff --git a/example/src/concepts/number.cpp b/example/src/concepts/number.cpp index c498686c..2062e9d0 100644 --- a/example/src/concepts/number.cpp +++ b/example/src/concepts/number.cpp @@ -8,7 +8,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex1] using num = std::false_type; @@ -17,7 +17,7 @@ using num = std::false_type; static_assert(metal::is_number::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex2] using num = std::integral_constant; @@ -26,14 +26,14 @@ using num = std::integral_constant; static_assert(metal::is_number::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [nex1] -struct num : +struct not_a_number : std::true_type {}; /// [nex1] -static_assert(!metal::is_number::value, ""); +static_assert(!metal::is_number::value, ""); } diff --git a/example/src/concepts/optional.cpp b/example/src/concepts/optional.cpp index 9e77663b..45ebe218 100644 --- a/example/src/concepts/optional.cpp +++ b/example/src/concepts/optional.cpp @@ -8,7 +8,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex1] struct opt @@ -20,7 +20,7 @@ struct opt static_assert(metal::is_just::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex2] using opt = void; //nothing - undefined ::type @@ -29,7 +29,7 @@ using opt = void; //nothing - undefined ::type static_assert(!metal::is_just::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex3] struct opt @@ -42,7 +42,7 @@ struct opt static_assert(!metal::is_just::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex4] struct optional1 diff --git a/example/src/concepts/pair.cpp b/example/src/concepts/pair.cpp index be6c0f94..94c8b03e 100644 --- a/example/src/concepts/pair.cpp +++ b/example/src/concepts/pair.cpp @@ -8,7 +8,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex1] template @@ -20,7 +20,7 @@ using pair = couple; static_assert(metal::is_pair_t::value, ""); } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [nex1] template diff --git a/example/src/concepts/value.cpp b/example/src/concepts/value.cpp index 345c9dc1..7e24df31 100644 --- a/example/src/concepts/value.cpp +++ b/example/src/concepts/value.cpp @@ -4,21 +4,21 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex1] using val = int; /// [ex1] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex2] using val = decltype(3.14); /// [ex2] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [ex3] struct val @@ -28,27 +28,27 @@ struct val /// [ex3] } -ANONYMOUS(struct) +HIDDEN(struct) { /// [nex1] -int val; +int not_a_value; /// [nex1] }; -ANONYMOUS(struct) +HIDDEN(struct) { static constexpr /// [nex2] -auto val = 3.14; +auto not_a_value = 3.14; /// [nex2] }; -ANONYMOUS(struct) +HIDDEN(struct) { /// [nex3] struct { //... -} val; +} not_a_value; /// [nex3] }; diff --git a/example/src/manual.cpp b/example/src/manual.cpp deleted file mode 100644 index 6a6416b8..00000000 --- a/example/src/manual.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright Bruno Dutra 2015 -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt) - -#include - -#include "example.hpp" - -/// [sum] -using sum = metal::add, metal::integer<4>>; -/// [sum] - -/// [first] -using left = metal::first; // evaluates to metal::integer<4> -/// [first] - -/// [second] -using right = metal::second; // evaluates to metal::integer<4> -/// [second] diff --git a/example/src/manual/homoiconicity.cpp b/example/src/manual/homoiconicity.cpp new file mode 100644 index 00000000..3e0a26b8 --- /dev/null +++ b/example/src/manual/homoiconicity.cpp @@ -0,0 +1,33 @@ +// Copyright Bruno Dutra 2015 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt) + +#include + +#include + +#include "example.hpp" + +HIDDEN(namespace) +{ +/// [1] +using sum = metal::add, metal::integer<3>, metal::integer<5>>; +/// [1] + +/// [2] +static_assert(std::is_same, metal::integer<10>>::value, ""); +/// [2] + +/// [3] +static_assert(metal::is_list::value, ""); +static_assert(metal::size_t::value == 3, ""); +/// [3] + +/// [4] +using sqsum = metal::transform_t>, sum>; +/// [4] + +/// [5] +static_assert(std::is_same, metal::integer<38>>::value, ""); +/// [5] +} diff --git a/example/src/number/arithmetic.cpp b/example/src/number/arithmetic.cpp index ea17d5ea..736c8adb 100644 --- a/example/src/number/arithmetic.cpp +++ b/example/src/number/arithmetic.cpp @@ -7,7 +7,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [inc] static_assert(std::is_same>, metal::integer<-9>>::value, ""); @@ -15,7 +15,7 @@ static_assert(std::is_same>, metal: /// [inc] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [dec] static_assert(std::is_same>, metal::integer<-11>>::value, ""); @@ -23,7 +23,7 @@ static_assert(std::is_same>, metal: /// [dec] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [neg] static_assert(std::is_same>, metal::integer<10>>::value, ""); @@ -31,7 +31,7 @@ static_assert(std::is_same>, metal: /// [neg] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [add] using x = metal::add_t< @@ -44,7 +44,7 @@ static_assert(std::is_same>::value, ""); /// [add] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [sub] using x = metal::sub_t< @@ -57,7 +57,7 @@ static_assert(std::is_same>::value, ""); /// [sub] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [mul] using x = metal::mul_t< @@ -70,7 +70,7 @@ static_assert(std::is_same>::value, ""); /// [mul] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [div] using x = metal::div_t< @@ -84,7 +84,7 @@ static_assert(!metal::is_just, metal::integ /// [div] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [mod] using x = metal::mod_t< @@ -98,7 +98,7 @@ static_assert(!metal::is_just, metal::integ /// [mod] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [pow] using x = metal::pow_t< @@ -108,7 +108,6 @@ using x = metal::pow_t< >; static_assert(std::is_same>::value, ""); -static_assert(!metal::is_just, metal::integer<0>>>::value, ""); static_assert(!metal::is_just, metal::integer<-3>>>::value, ""); /// [pow] } diff --git a/example/src/number/comparison.cpp b/example/src/number/comparison.cpp index d37aeb0a..9d56f62b 100644 --- a/example/src/number/comparison.cpp +++ b/example/src/number/comparison.cpp @@ -6,7 +6,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [equal_to] static_assert(std::is_same, metal::number>, metal::boolean>::value, ""); @@ -14,7 +14,7 @@ static_assert(std::is_same, me /// [equal_to] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [greater] static_assert(std::is_same, metal::number>, metal::boolean>::value, ""); @@ -22,7 +22,7 @@ static_assert(std::is_same, met /// [greater] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [less] static_assert(std::is_same, metal::number>, metal::boolean>::value, ""); diff --git a/example/src/number/enumerate.cpp b/example/src/number/enumerate.cpp index 4a861cf0..9c792742 100644 --- a/example/src/number/enumerate.cpp +++ b/example/src/number/enumerate.cpp @@ -6,7 +6,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [enumerate] using x = metal::enumerate_t>; diff --git a/example/src/number/logical.cpp b/example/src/number/logical.cpp index b6061072..1382bffa 100644 --- a/example/src/number/logical.cpp +++ b/example/src/number/logical.cpp @@ -7,7 +7,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [not_] static_assert(std::is_same>, metal::boolean>::value, ""); @@ -17,7 +17,7 @@ static_assert(std::is_same>, metal::bo /// [not_] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [and_] using x = metal::and_t< @@ -30,7 +30,7 @@ static_assert(std::is_same>::value, ""); /// [and_] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [or_] using x = metal::or_t< diff --git a/example/src/number/number.cpp b/example/src/number/number.cpp index b7f54a30..ef05b43a 100644 --- a/example/src/number/number.cpp +++ b/example/src/number/number.cpp @@ -6,7 +6,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [is_number] static_assert(metal::is_number_t>::value, ""); diff --git a/example/src/optional/conditional.cpp b/example/src/optional/conditional.cpp index 900abbbd..ffb6aa49 100644 --- a/example/src/optional/conditional.cpp +++ b/example/src/optional/conditional.cpp @@ -6,7 +6,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [conditional] //TODO diff --git a/example/src/optional/eval.cpp b/example/src/optional/eval.cpp index d694328b..aa695fda 100644 --- a/example/src/optional/eval.cpp +++ b/example/src/optional/eval.cpp @@ -6,7 +6,7 @@ #include "example.hpp" -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [eval] struct none diff --git a/example/src/optional/optional.cpp b/example/src/optional/optional.cpp index a6a20f13..241f3fb4 100644 --- a/example/src/optional/optional.cpp +++ b/example/src/optional/optional.cpp @@ -6,7 +6,7 @@ #include "example.hpp" -ANONYMOUS(struct) +HIDDEN(struct) { /// [just] using none = metal::just<>; @@ -18,7 +18,7 @@ static_assert(std::is_same::value, ""); /// [just] }; -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [is_just] struct none @@ -34,7 +34,7 @@ static_assert(metal::is_just::value, ""); /// [is_just] } -ANONYMOUS(namespace) +HIDDEN(namespace) { /// [optional] struct none diff --git a/example/src/tutorial/literal.cpp b/example/src/tutorial/literal.cpp new file mode 100644 index 00000000..ffa7f810 --- /dev/null +++ b/example/src/tutorial/literal.cpp @@ -0,0 +1,329 @@ +// Copyright Bruno Dutra 2015 +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSEmetal::_1_0.txt) + +#include + +#include +#include + +#include "example.hpp" + +#if 0 +///[naive] +constexpr auto operator ""_c(long long i) + -> std::integral_constant { + return {}; +} +///[naive] +#endif + +///[raw] +template +constexpr auto operator ""/**/_raw() + -> metal::list...> { + return {}; +} +///[raw] + +///[raw_examples_1] +static_assert(std::is_same< + decltype(42_raw), + metal::list, metal::character<'2'>> +>::value, ""); + +static_assert(std::is_same< + decltype(0x42_raw), + metal::list< + metal::character<'0'>, metal::character<'x'>, + metal::character<'4'>,metal::character<'2'> + > +>::value, ""); +///[raw_examples_1] + +#ifdef __cpp_digit_separators +///[raw_examples_2] +static_assert(std::is_same< + decltype(4'2_raw), + metal::list, metal::character<'\''>, metal::character<'2'>> +>::value, ""); +///[raw_examples_2] + +HIDDEN(namespace) +{ +///[remove] +using tokens = metal::list< + metal::character<'4'>, + metal::character<'\''>, + metal::character<'2'> +>; + +static_assert(std::is_same< + metal::remove_t>, + metal::list, metal::character<'2'>> +>::value, ""); +///[remove] +} +#endif + +///[to_number] +template +struct to_number : + metal::conditional< + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number, + metal::equal_to_t>, metal::number + > +{}; +///[to_number] + +HIDDEN(namespace) +{ +///[transform_1] +using digits = metal::list, metal::character<'2'>>; + +static_assert(std::is_same< + metal::transform_t, digits>, + metal::list, metal::number> +>::value, ""); +///[transform_1] +} + +HIDDEN(namespace) +{ +///[reverse] +using digits = metal::list, metal::number>; + +static_assert(std::is_same< + metal::reverse_t, + metal::list, metal::number> +>::value, ""); +///[reverse] +} + +HIDDEN(namespace) +{ +///[enumerate] +using digits = metal::list, metal::number>; + +static_assert(std::is_same< + metal::enumerate_t, metal::size_t>, + metal::list, metal::number> +>::value, ""); +///[enumerate] +} + +HIDDEN(namespace) +{ +///[transform_2] +using radix = metal::number; +using digits = metal::list, metal::number>; +using exponents = metal::list, metal::number>; + +static_assert(std::is_same< + metal::transform_t< + metal::mul>, + digits, + exponents + >, + metal::list, metal::number> +>::value, ""); +///[transform_2] +} + +HIDDEN(namespace) +{ +///[sum] +using terms = metal::list, metal::number>; + +static_assert(std::is_same< + metal::apply_t, terms>, + metal::number +>::value, ""); +///[sum] +} + +///[compute] +template +struct compute : + metal::apply< + metal::lambda, + metal::transform_t< + metal::mul>, + metal::reverse_t, + metal::enumerate_t< + metal::number, + metal::size_t + > + > + > +{}; +///[compute] + +///[parse_digits] +template +struct parse_digits : + metal::transform< + to_number, + metal::remove_t, metal::character<'\''>> + > +{}; + +template +using parse_digits_t = typename parse_digits::type; +///[parse_digits] + +///[make_number] +template +struct make_number : + compute, parse_digits_t> +{}; + +template +struct make_number, tokens...> : + compute, parse_digits_t> +{}; + +template +struct make_number, metal::character<'x'>, tokens...> : + compute, parse_digits_t> +{}; + +template +struct make_number, metal::character<'X'>, tokens...> : + compute, parse_digits_t> +{}; + +template +struct make_number, metal::character<'b'>, tokens...> : + compute, parse_digits_t> +{}; + +template +struct make_number, metal::character<'B'>, tokens...> : + compute, parse_digits_t> +{}; + +template +using make_number_t = typename make_number::type; +///[make_number] + +///[_c] +template +constexpr auto operator ""/**/_c() + -> make_number_t...> { + return {}; +} +///[_c] + +///[test_1] +static_assert(std::is_same< + decltype(01234567_c), //octal + metal::number +>::value, ""); + +static_assert(std::is_same< + decltype(123456789_c), //decimal + metal::number +>::value, ""); + +static_assert(std::is_same< + decltype(0xABCDEF_c), //hexadecimal + metal::number +>::value, ""); +///[test_1] + +static_assert(std::is_same< + decltype(0Xabcdef_c), + metal::number +>::value, ""); + + +#if __cpp_binary_literals +///[test_2] +static_assert(std::is_same< + decltype(0b111101101011011101011010101100101011110001000111000111000111000_c), + metal::number +>::value, ""); +///[test_2] + +static_assert(std::is_same< + decltype(0B111101101011011101011010101100101011110001000111000111000111000_c), + metal::number +>::value, ""); +#endif + +#ifdef __cpp_digit_separators +///[test_3] +static_assert(std::is_same< + decltype(1'2'3'4'5'6'7'8'9_c), + metal::number +>::value, ""); +///[test_3] +#endif + +#if __cpp_constexpr < 201304 +template +struct SuperTuple : + std::tuple +{ + template + constexpr SuperTuple(U&&... args) : + std::tuple(std::forward(args)...) + {} + + template + constexpr auto operator [](metal::number) const + -> metal::at_t> { + return std::get(*this); + } +}; +#else +///[super_tuple] +template +struct SuperTuple : + std::tuple +{ + using std::tuple::tuple; + + template + constexpr auto operator [](metal::number) + -> metal::at_t>& { + return std::get(*this); + } +}; +///[super_tuple] +#endif + +///[teaser_1] +static_assert(std::get<1>(std::tuple{42, 'a', 2.5}) == 'a', ""); +///[teaser_1] + +#if 0 +///[teaser_2] +static_assert(SuperTuple{42, 'a', 2.5}[1] == 'a', ""); +///[teaser_2] +#endif + +///[teaser_3] +static_assert(SuperTuple{42, 'a', 2.5}[1_c] == 'a', ""); +///[teaser_3] diff --git a/include/metal/lambda.hpp b/include/metal/lambda.hpp index 3405afbf..440afc34 100644 --- a/include/metal/lambda.hpp +++ b/include/metal/lambda.hpp @@ -5,7 +5,6 @@ #ifndef METAL_LAMBDA_HPP #define METAL_LAMBDA_HPP -#include #include #include #include diff --git a/include/metal/list.hpp b/include/metal/list.hpp index 01420342..ec6fbf82 100644 --- a/include/metal/list.hpp +++ b/include/metal/list.hpp @@ -6,6 +6,7 @@ #define METAL_LIST_HPP #include +#include #include #include #include diff --git a/include/metal/lambda/apply.hpp b/include/metal/list/apply.hpp similarity index 91% rename from include/metal/lambda/apply.hpp rename to include/metal/list/apply.hpp index d4563312..4f1cb0eb 100644 --- a/include/metal/lambda/apply.hpp +++ b/include/metal/list/apply.hpp @@ -2,8 +2,8 @@ // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt) -#ifndef METAL_LAMBDA_APPLY_HPP -#define METAL_LAMBDA_APPLY_HPP +#ifndef METAL_LIST_APPLY_HPP +#define METAL_LIST_APPLY_HPP namespace metal { @@ -13,12 +13,12 @@ namespace metal struct apply; } - /// \ingroup lambda + /// \ingroup list /// ... template using apply = detail::apply; - /// \ingroup lambda + /// \ingroup list /// Eager adaptor for \ref apply. template using apply_t = typename metal::apply::type; diff --git a/include/metal/list/copy_if.hpp b/include/metal/list/copy_if.hpp index 39ad7db8..7ab1fee4 100644 --- a/include/metal/list/copy_if.hpp +++ b/include/metal/list/copy_if.hpp @@ -26,11 +26,11 @@ namespace metal #include #include +#include #include #include #include #include -#include #include #include #include @@ -42,7 +42,7 @@ namespace metal template struct copy_if : invoke< - copy<_1, apply>, transform<_2, _3>>>, + copy<_1, apply>, transform<_3, _2>>>, to, from, conditional, list<_1>, list<>> > {}; diff --git a/include/metal/list/replace_if.hpp b/include/metal/list/replace_if.hpp index 7564e275..32a1e83a 100644 --- a/include/metal/list/replace_if.hpp +++ b/include/metal/list/replace_if.hpp @@ -25,9 +25,9 @@ namespace metal } #include +#include #include #include -#include #include #include #include @@ -40,7 +40,7 @@ namespace metal template struct replace_if : invoke< - copy<_1, apply<_2, transform<_1, _3>>>, + copy<_1, apply<_2, transform<_3, _1>>>, list, lambda, conditional< diff --git a/include/metal/list/slice.hpp b/include/metal/list/slice.hpp index 047ca480..8841bb3f 100644 --- a/include/metal/list/slice.hpp +++ b/include/metal/list/slice.hpp @@ -61,8 +61,8 @@ namespace metal copy< expr, transform_t< - enumerate_t, number, number>, - at>, mod<_1, size_t>>> + at>, mod<_1, size_t>>>, + enumerate_t, number, number> > > {}; diff --git a/include/metal/list/transform.hpp b/include/metal/list/transform.hpp index 635ed178..580d205e 100644 --- a/include/metal/list/transform.hpp +++ b/include/metal/list/transform.hpp @@ -9,40 +9,49 @@ namespace metal { namespace detail { - template + template struct transform; } /// \ingroup list /// ... - template - using transform = detail::transform; + template + using transform = detail::transform; /// \ingroup list /// Eager adaptor for \ref transform. - template - using transform_t = typename metal::transform::type; + template + using transform_t = typename metal::transform::type; } +#include +#include +#include +#include #include #include #include #include +#include namespace metal { namespace detail { - template - struct transform + template + struct transform : + invoke< + transform<_1, transpose<_2>>, + apply, _1>, list + > {}; template< + typename lbd, template class expr, - typename... vals, - typename lbd + typename... vals > - struct transform, lbd> : + struct transform> : invoke>>, invoke...> {}; } diff --git a/include/metal/list/transpose.hpp b/include/metal/list/transpose.hpp index 541b004d..a5a24b83 100644 --- a/include/metal/list/transpose.hpp +++ b/include/metal/list/transpose.hpp @@ -72,8 +72,8 @@ namespace metal boolean<(sizeof...(tail) > 1)> > : transform< - indices_t, - defer_t, _1>, at, _1>...>> + defer_t, _1>, at, _1>...>>, + indices_t > {}; diff --git a/include/metal/number/arithmetic/add.hpp b/include/metal/number/arithmetic/add.hpp index 3b164864..d12f4f78 100644 --- a/include/metal/number/arithmetic/add.hpp +++ b/include/metal/number/arithmetic/add.hpp @@ -34,10 +34,7 @@ namespace metal /// > /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/arithmetic/dec.hpp b/include/metal/number/arithmetic/dec.hpp index b8f3b693..c51408cd 100644 --- a/include/metal/number/arithmetic/dec.hpp +++ b/include/metal/number/arithmetic/dec.hpp @@ -27,16 +27,10 @@ namespace metal /// If `val` is a \number, but not a boolean, then equivalent to /// \code /// struct result : - /// metal::number< - /// val::value_type, - /// static_cast(val::value - 1) - /// > + /// metal::number /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/arithmetic/div.hpp b/include/metal/number/arithmetic/div.hpp index 7c3028ff..72a5b485 100644 --- a/include/metal/number/arithmetic/div.hpp +++ b/include/metal/number/arithmetic/div.hpp @@ -35,10 +35,7 @@ namespace metal /// > /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/arithmetic/inc.hpp b/include/metal/number/arithmetic/inc.hpp index 3fb0e0c5..08c5de41 100644 --- a/include/metal/number/arithmetic/inc.hpp +++ b/include/metal/number/arithmetic/inc.hpp @@ -27,16 +27,10 @@ namespace metal /// If `val` is a \number, but not a boolean, then equivalent to /// \code /// struct result : - /// metal::number< - /// val::value_type, - /// static_cast(val::value + 1) - /// > + /// metal::number /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/arithmetic/mod.hpp b/include/metal/number/arithmetic/mod.hpp index 8c4020bb..5a75f16f 100644 --- a/include/metal/number/arithmetic/mod.hpp +++ b/include/metal/number/arithmetic/mod.hpp @@ -35,10 +35,7 @@ namespace metal /// > /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/arithmetic/mul.hpp b/include/metal/number/arithmetic/mul.hpp index 236784ee..074ad6ba 100644 --- a/include/metal/number/arithmetic/mul.hpp +++ b/include/metal/number/arithmetic/mul.hpp @@ -34,10 +34,7 @@ namespace metal /// > /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/arithmetic/neg.hpp b/include/metal/number/arithmetic/neg.hpp index ebd8f58c..dc143fe9 100644 --- a/include/metal/number/arithmetic/neg.hpp +++ b/include/metal/number/arithmetic/neg.hpp @@ -27,16 +27,10 @@ namespace metal /// If `val` is a \number, but not boolean, then equivalent to /// \code /// struct result : - /// metal::number< - /// val::value_type, - /// static_cast(-val::value) - /// > + /// metal::number /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/arithmetic/pow.hpp b/include/metal/number/arithmetic/pow.hpp index 4806e0bf..a8e45808 100644 --- a/include/metal/number/arithmetic/pow.hpp +++ b/include/metal/number/arithmetic/pow.hpp @@ -35,12 +35,9 @@ namespace metal /// > /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// \note{ - /// Borrowing from Fortran, `x ** y` shall be understood as + /// Borrowing from Fortran, `x ** y` means /// `x` raised to the power of `y`. /// } /// \danger{ @@ -71,12 +68,10 @@ namespace metal namespace detail { template - constexpr T pow_impl(T base, T exp, T result = 1){ - return !exp ? - result : - exp < 0 ? - pow_impl(1/(base*base), -exp/2, -exp%2 ? result/base : result) : - pow_impl(base*base, exp/2, exp%2 ? result*base : result); + constexpr T pow_impl(T base, T exp, T result = 1) { + return exp == 1 ? + base*result : + pow_impl(base*base, exp/2, exp%2 ? result*base : result); } template @@ -90,9 +85,13 @@ namespace metal template struct pow, number, nums...> : - pow< - number(vx, vy)>, - nums... + conditional< + boolean, + pow, nums...>, + pow< + number(vx, vy)>, + nums... + > > {}; @@ -100,9 +99,29 @@ namespace metal struct pow, number, nums...> : conditional< boolean<(vy > 0)>, - pow, nums...> + pow, nums...> > {}; + + template + struct pow, number, nums...> : + pow, nums...> + {}; + + template + struct pow, number, nums...> : + pow, nums...> + {}; + + template + struct pow, number, nums...> : + pow, nums...> + {}; + + template + struct pow, number, nums...> : + pow, nums...> + {}; } } diff --git a/include/metal/number/arithmetic/sub.hpp b/include/metal/number/arithmetic/sub.hpp index 221b0107..29536eea 100644 --- a/include/metal/number/arithmetic/sub.hpp +++ b/include/metal/number/arithmetic/sub.hpp @@ -34,10 +34,7 @@ namespace metal /// > /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/comparison/equal_to.hpp b/include/metal/number/comparison/equal_to.hpp index 098195b9..6a332f91 100644 --- a/include/metal/number/comparison/equal_to.hpp +++ b/include/metal/number/comparison/equal_to.hpp @@ -30,10 +30,7 @@ namespace metal /// metal::boolean /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/comparison/greater.hpp b/include/metal/number/comparison/greater.hpp index 83ccb9db..8b02ece7 100644 --- a/include/metal/number/comparison/greater.hpp +++ b/include/metal/number/comparison/greater.hpp @@ -30,10 +30,7 @@ namespace metal /// metal::boolean<(val1::value > val2::value)> /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/comparison/less.hpp b/include/metal/number/comparison/less.hpp index 11c225a4..c1c2b992 100644 --- a/include/metal/number/comparison/less.hpp +++ b/include/metal/number/comparison/less.hpp @@ -30,10 +30,7 @@ namespace metal /// metal::boolean<(val1::value < val2::value)> /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/enumerate.hpp b/include/metal/number/enumerate.hpp index f7bd7976..4291b85b 100644 --- a/include/metal/number/enumerate.hpp +++ b/include/metal/number/enumerate.hpp @@ -32,10 +32,7 @@ namespace metal /// metal::enumerate, size> /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// ________________________________________________________________________ /// @@ -93,10 +90,7 @@ namespace metal /// > /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/logical/and.hpp b/include/metal/number/logical/and.hpp index 8fff2890..6f66c089 100644 --- a/include/metal/number/logical/and.hpp +++ b/include/metal/number/logical/and.hpp @@ -31,10 +31,7 @@ namespace metal /// metal::boolean /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/logical/not.hpp b/include/metal/number/logical/not.hpp index b19284a2..061dbd0b 100644 --- a/include/metal/number/logical/not.hpp +++ b/include/metal/number/logical/not.hpp @@ -30,10 +30,7 @@ namespace metal /// metal::boolean /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/logical/or.hpp b/include/metal/number/logical/or.hpp index 8ee84155..cc3a93e4 100644 --- a/include/metal/number/logical/or.hpp +++ b/include/metal/number/logical/or.hpp @@ -31,10 +31,7 @@ namespace metal /// metal::boolean /// {}; /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; - /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// Example /// ------- diff --git a/include/metal/number/number.hpp b/include/metal/number/number.hpp index 25559e9c..98349ef6 100644 --- a/include/metal/number/number.hpp +++ b/include/metal/number/number.hpp @@ -24,6 +24,11 @@ namespace metal template using integer = metal::number; + /// \ingroup number + /// Standard representation for [characters](\numbers). + template + using character = metal::number; + namespace detail { template diff --git a/include/metal/optional/conditional.hpp b/include/metal/optional/conditional.hpp index 9b4a164b..72087f4e 100644 --- a/include/metal/optional/conditional.hpp +++ b/include/metal/optional/conditional.hpp @@ -26,7 +26,9 @@ namespace metal /// \par Semantics: /// Equivalent to /// \code - /// using result = metal::conditional; + /// struct result : + /// metal::conditional + /// {}; /// \endcode /// /// ________________________________________________________________________ @@ -39,17 +41,18 @@ namespace metal /// \par Semantics: /// If `val` is a \number and `!!val::value == true`, then equivalent to /// \code - /// using result = metal::optional; + /// struct result : + /// metal::optional + /// {}; /// \endcode /// otherwise, if `val` is a \number and `val::value == false`, /// then equivalent to /// \code - /// using result = metal::optional; - /// \endcode - /// otherwise, equivalent to - /// \code - /// using result = metal::nothing; + /// struct result : + /// metal::optional + /// {}; /// \endcode + /// otherwise, equivalent to `metal::nothing` /// /// ________________________________________________________________________ /// @@ -61,9 +64,11 @@ namespace metal /// \par Semantics: /// Equivalent to /// \code - /// using result = metal::conditional< - /// val1, val2, metal::conditional - /// >; + /// struct result : + /// metal::conditional< + /// val1, val2, metal::conditional + /// > + /// {}; /// \endcode /// /// Example diff --git a/include/metal/optional/eval.hpp b/include/metal/optional/eval.hpp index 0db03e5a..1ff77f78 100644 --- a/include/metal/optional/eval.hpp +++ b/include/metal/optional/eval.hpp @@ -28,7 +28,7 @@ namespace metal /// using result = typename opt::type /// \endcode /// - /// \danger{Evaluating an empty optional results in a compile time error.} + /// \danger{Evaluating an empty optional leads to a compile time error.} /// /// ________________________________________________________________________ /// diff --git a/test/src/metal/list.cpp b/test/src/metal/list.cpp index 02a6f1e6..aa5be06e 100644 --- a/test/src/metal/list.cpp +++ b/test/src/metal/list.cpp @@ -10,11 +10,11 @@ #include "test.hpp" #define MATRIX(M, N) \ - ASSERT((metal::flatten_t>>), (LIST(M))); \ + ASSERT((metal::flatten_t, LIST(M)>>), (LIST(M))); \ ASSERT((metal::flatten_t, metal::lambda>>), (metal::list)); \ ASSERT((metal::flatten_t>>>), (metal::list)); \ ASSERT((metal::slice_t, metal::size_t>), (LIST(M))); \ - ASSERT((metal::transform_t, metal::at, ARG(0)>>), (LIST(M))); \ + ASSERT((metal::transform_t, ARG(0)>, SEQ(M)>), (LIST(M))); \ ASSERT((metal::accumulate_t, metal::push_front, NUM(M), NUM(0)>), (metal::accumulate_t, metal::push_back>)); \ ASSERT((metal::reduce_t, metal::lambda, NUM(INC(M)), NUM(0)>), (metal::reduce_t>, metal::lambda>)); \ ASSERT((metal::insert_t), (metal::push_back_t)); \ diff --git a/test/src/metal/lambda/apply.cpp b/test/src/metal/list/apply.cpp similarity index 99% rename from test/src/metal/lambda/apply.cpp rename to test/src/metal/list/apply.cpp index 9f408175..32959635 100644 --- a/test/src/metal/lambda/apply.cpp +++ b/test/src/metal/list/apply.cpp @@ -2,7 +2,7 @@ // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt) -#include +#include #include #include diff --git a/test/src/metal/map.cpp b/test/src/metal/map.cpp index 1ea5f8a7..754c2815 100644 --- a/test/src/metal/map.cpp +++ b/test/src/metal/map.cpp @@ -9,8 +9,8 @@ #include "test.hpp" #define MATRIX(M, N) \ - ASSERT((metal::transform_t>), (metal::keys_t)); \ - ASSERT((metal::transform_t>), (metal::values_t)); \ + ASSERT((metal::transform_t, MAP(M)>), (metal::keys_t)); \ + ASSERT((metal::transform_t, MAP(M)>), (metal::values_t)); \ ASSERT((metal::first_t>), (metal::keys_t)); \ ASSERT((metal::second_t>), (metal::values_t)); \ ASSERT((metal::at_t>), (PAIR(N))); \ diff --git a/test/src/metal/number.cpp b/test/src/metal/number.cpp index 7587c2bf..bfa5c236 100644 --- a/test/src/metal/number.cpp +++ b/test/src/metal/number.cpp @@ -3,7 +3,7 @@ // (See accompanying file LICENSE.txt or copy at http://boost.org/LICENSE_1_0.txt) #include -#include +#include #include #include "test.hpp" diff --git a/test/src/metal/number/arithmetic.cpp b/test/src/metal/number/arithmetic.cpp index a147d522..f9294f5a 100644 --- a/test/src/metal/number/arithmetic.cpp +++ b/test/src/metal/number/arithmetic.cpp @@ -36,8 +36,8 @@ ASSERT((metal::is_just_t>), (BOOL(N > 0))); \ ASSERT((metal::is_just_t>), (BOOL(!M ^ !N))); \ ASSERT((metal::is_just_t>), (BOOL(!M ^ !N))); \ - ASSERT((metal::is_just_t>), (BOOL(!M ^ !N))); \ - ASSERT((metal::is_just_t>>), (BOOL(!M))); \ + ASSERT((metal::is_just_t>), (BOOL(M || N))); \ + ASSERT((metal::is_just_t>>), (BOOL(!M || !N))); \ ASSERT((metal::equal_to_t>, NUM(N)>), (TRUE)); \ ASSERT((metal::equal_to_t, NUM(INC(N))>), (TRUE)); \ ASSERT((metal::equal_to_t, NUM(N)>), (TRUE)); \ @@ -52,6 +52,7 @@ ASSERT((metal::equal_to_t, NUM(0)>), (TRUE)); \ ASSERT((metal::equal_to_t, NUM(0)>), (TRUE)); \ ASSERT((metal::equal_to_t, NUM(INC(N))>, metal::mod_t>, NUM(M)>), (TRUE)); \ + ASSERT((metal::equal_to_t, metal::integer>), (TRUE)); \ ASSERT((metal::equal_to_t, NUM(1)>), (TRUE)); \ ASSERT((metal::equal_to_t, metal::integer<1 << N>>), (TRUE)); \ /**/ diff --git a/test/src/metal/number/number.cpp b/test/src/metal/number/number.cpp index ff22d662..56a21ae0 100644 --- a/test/src/metal/number/number.cpp +++ b/test/src/metal/number/number.cpp @@ -18,8 +18,9 @@ ASSERT((metal::is_number_t), (FALSE)); \ ASSERT((metal::is_number_t), (FALSE)); \ ASSERT((metal::is_number_t>), (TRUE)); \ - ASSERT((metal::is_number_t>), (TRUE)); \ ASSERT((metal::is_number_t>), (TRUE)); \ + ASSERT((metal::is_number_t>), (TRUE)); \ + ASSERT((metal::is_number_t>), (TRUE)); \ /**/ GEN(MATRIX)