⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 introduction.sgml

📁 boost库提供标准的C++ API 配合dev c++使用,功能更加强大
💻 SGML
📖 第 1 页 / 共 2 页
字号:
// specialization to peel apart the cons list
template< typename First, typename Rest >
struct largest< cons<First,Rest> >
    : choose_larger< First, typename largest<Rest>::type >
{
    // type inherited from base
};

// specialization for loop termination
template< typename First >
struct largest< cons<First,nil> >
{
    typedef First type;
};

int main()
{
    // print the name of the largest of my_types
    std::cout
        << typeid(largest<my_types>::type).name()
        << std::endl
        ;
}
]]>
</>
</>

<para>
There are several things worth noticing about this code:
</>

<itemizedlist mark="box">

<listitem><para>
It uses a few ad-hoc, esoteric techniques, or <quote>hacks</>. The default template argument <literal>choose1</> (labeled <quote>hands off!</>) is one example. Without it, we would have needed yet another template to provide the implementation of <literal>choose_larger</>, or we would have had to provide the computation explicitly as a   parameter to the template - perhaps not bad for this example, but it would make <literal>choose_larger</> much less useful and more error-prone. The other hack is the derivation of a specialization of <literal>largest</> from <literal>choose_larger</>. This is a code-saving device which allows the programmer to avoid writing <quote><literal>typedef
  typename </>...<literal>::type type</></> in the template body.
</></>

<listitem><para>
Even this simple metaprogram uses three separate partial specializations. The <literal>largest</> &mfn; uses <emphasis>two</> specializations. One might expect that this indicates there are two termination conditions, but there are not: one specialization is needed simply to deal with access to the sequence elements. These   specializations make the code difficult to read by spreading the definition of a single &mfn; over several &Cxx; template definitions. Also, because they are <emphasis>partial</> specializations, they make the code unusable for a large community of &Cxx; programmers whose compilers don't support that feature.
</></>

</itemizedlist>

<para>
While these techniques are, of course, a valuable part of the arsenal of any good &Cxx; metaprogrammer, their use tends to make programs written in what is already an unusual style harder-to-read and harder-to-write. By encapsulating commonly-used structures and dealing with loop terminations internally, the &MPL; reduces the need for both tricky hacks and for template specializations.
</>
</section>

</section>

<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section -->
<section id="intro.whymetaprog">
<title>Why metaprogramming?</>

<!--
maybe we don't need another example of a metaprogram given what
we've done above? We could rewrite and cut most of this section...
-->

<para>
It's worth asking why anyone would want to do this. After all, even a simple toy example like the factorial &mfn; is somewhat esoteric. To show how the type computation can be put to work, let's examine a simple example. The following code produces an array containing all possible permutations of another array:
</>

<programlisting>
<![CDATA[
// can't return an array in C++, so we need this wrapper
template< typename T >
struct wrapper
{
    T x;
};

// return an array of the N! permutations of 'in'
template< typename T >
wrapper< typename permutation_holder<T>::type >
all_permutations(T const& in)
{
    wrapper<typename permutation_holder<T>::type> result;

    // copy the unpermutated array to the first result element
    unsigned const N = sizeof(T) / sizeof(**result.x);
    std::copy(&*in, &*in + N, result.x[0]);

    // enumerate the permutations
    unsigned const result_size = sizeof(result.x) / sizeof(T);
    for (T* dst = result.x + 1; dst != result.x + result_size; ++dst)
    {
        T* src = dst - 1;
        std::copy(*src, *src + N, *dst);
        std::next_permutation(*dst, *dst + N);
    }
    return result;
}
]]>
</>

<!-- ...up to this point -->

<para>
The runtime definition of <literal>factorial</> would be useless in <literal>all_permutations</> above, since in &Cxx; the sizes of array members must be computed at compile-time. However, there are alternative approaches; how could we avoid &mping;, and what would the consequences be?
</>

<orderedlist>

<listitem>
<para>
We could write programs to interpret the &mdat; directly. In our factorial example, the array size could have been a runtime quantity; then we'd have been able to use the straightforward factorial function. However, that would imply the use of dynamic allocation, which is often expensive.
</>
<para>
To carry this further, YACC might be rewritten to accept a pointer-to-function returning tokens from the stream to be parsed, and a string containing the grammar description. This approach, however, would impose unacceptable runtime costs for most applications: either the parser would have to treat the grammar nondeterministically, exploring the grammar for each parse, or it would have to begin by replicating at runtime the substantial table-generation and optimization work of the existing YACC for each input grammar.
</>
</>

<listitem>
<para>
We could replace the compile-time computation with our own analysis. After all, the size of arrays passed to
  <literal>all_permutations</> are always known at compile-time, and thus can be known to its user. We could ask the user to supply the result type explicitly:
</>

<programlisting>
<![CDATA[
template< typename Result, typename T >
Result all_permutations(T const& input);
]]>
</>

<para>
The costs to this approach are obvious: we give up expressivity (by requiring the user to explicitly specify implementation details), and correctness (by allowing the user to specify them incorrectly). Anyone who has had to write parser tables by hand will tell you that the impracticality of this approach is the very reason of YACC's existence.
</>
<para>
In a language such as &Cxx;, where the &mdat; can be expressed in the same language as the rest of the user's program, expressivity is further enhanced: the user can invoke metaprograms directly, without learning a foreign syntax or interrupting the flow of her code.
</>
</>

</orderedlist>

<para>
So, the motivation for &mping; comes down to the combination of three factors: efficiency, expressivity, and correctness. While in classical programming there is always a tension between expressivity and correctness on one hand and efficiency on the other, in the &mping; world we wield new power: we can move the computation required for
expressivity from runtime to compile-time.
</>
</section>

<!-- ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| section -->
<section id="intro.whylibrary">
<title>Why a metaprogramming <emphasis>library</>?</>

<para>
One might just as well ask why we need any generic library: 
</>

<itemizedlist mark="box">

<listitem>
<para>
Quality. Code that is appropriate for a general-purpose library is usually incidental to the purpose of its users. To a library developer, it is the central mission. On average, the containers and algorithms provided by any given &Cxx; standard library implementation are more-flexible and better-implemented than the project-specific implementations which abound, because library development was treated as an end in itself rather than a task incidental to the development of some other application. With a centralized implementation for any given function, optimizations and improvements are more likely to have been applied.
</>
</>

<listitem>
<para>
Re-use. More important even than the re-use of code which all libraries provide, a well-designed generic library establishes a <emphasis>framework of concepts and idioms</> which establishes a reusable mental model for approaching problems. Just as the &Cxx; Standard Template Library gave us iterator concepts and a function object protocol, the &BMPL; provides type-iterators and metafunction class protocol. A well-considered framework of idioms saves the metaprogrammer from considering irrelevant implementation details and allows her to concentrate on the problem at hand.
</>
</>

<listitem>
<para>
Portability. A good library can smooth over the ugly realities of platform differences. While in theory a &mping; library is fully generic and shouldn't be concerned with these issues, in practice support for templates remains inconsistent even four years after standardization. This should perhaps not be surprising: &Cxx; templates are the language's furthest-reaching and most complicated feature, which largely accounts for the power of &mping; in &Cxx;.
</>
</>

<listitem>
<para>
Fun. Repeating the same idioms over and over is <emphasis>tedious</>. It makes programmers tired and reduces productivity. Furthermore, when programmers get bored they get sloppy, and buggy code is even more costly than slowly-written code. Often the most useful libraries are simply patterns that have been <quote>plucked</> by an astute programmer from a sea of repetition. The &MPL; helps to reduce boredom by eliminating the need for the most commonly-repeated boilerplate coding patterns.
</>
</>

</itemizedlist>

<para>
As one can see, the &MPL;'s development is motivated primarily by the same practical, real-world considerations that justify the development of any other library. Perhaps this is an indication that template &mping; is finally ready to leave the realm of the esoteric and enter the lingua franca of every day programmers. 
</>

<!-- probably this paragraph would be better in the conclusions -->
</section>

</section>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -