Section 8.2.  Using Tools for Diagnostic Analysis
Team LiB
Previous Section Next Section

8.2. Using Tools for Diagnostic Analysis

Though their efforts sometimes backfire, compiler vendors are clearly going out of their way to address the problem of unreadable template error messages. That said, even the best error message formats can still leave a lot to be desired when a bug bites you from deep within a nested template instantiation. Fortunately, software tools can be an immense help, if you follow three suggestions.

8.2.1. Get a Second Opinion

Our first recommendation is to keep a few different compilers on hand, just for debugging purposes. If one compiler emits an inscutable error message, another one will likely do better. When something goes wrong, a compiler may guess at what you meant in order to report the mistake, and it often pays to have several different guesses. Also, many compilers have intrinsic deficiencies when it comes to error reporting. For example, though it is an otherwise excellent compilerand one of the very fastest in our timing testsMetrowerks CodeWarrior Pro 9 often fails to output filenames and line numbers for each "frame" of its instantiation backtrace, which can make the offending source code hard to find. If you need to trace the source of the error, you may want to try a different toolset.

Tip

If you don't have the budget to invest in more tools, we suggest trying to find a recent version of GCC that runs on your platform. All versions of GCC are available for free; Windows users should get the MinGW (http://www.mingw.org) or Cygwin (http://www.cygwin.com) variants. If you can't bear to install another compiler on your machine, Comeau Computing will let you try an online version of their compiler at http://www.comeaucomputing.com/tryitout. Because Comeau C++ is based on the highly conformant EDG front-end, it provides an excellent way to get a quick read on whether your code is likely to comply with the C++ standard.


8.2.2. Use Navigational Aids

For traversing instantiation stack backtraces, it's crucial to have an environment that helps you to see the source line associated with an error message. If you're one of those people who usually compiles from a command shell, you may want to issue those commands from within some kind of integrated development environment (IDE), just to avoid having to manually open files in an editor and look up line numbers. Many IDEs allow a variety of toolsets to be plugged in, but for debugging metaprograms it's important that the IDE can conveniently step between messages in the various compilers' diagnostic formats. Emacs, for example, uses an extensible set of regular expressions to extract filenames and line numbers from error messages, so it can be tuned to work with any number of compilers.

8.2.3. Clean Up the Landscape

Finally, we suggest the use of a post-processing filter such as TextFilt (http://textfilt.sourceforge.net) or STLFilt (http://www.bdsoft.com/tools/stlfilt.html). Both of these filters were originally designed to help programmers make sense of the types in their STL error messages. Their most basic features include the automatic elision of default arguments from specializations of known templates, and typedef substitution for std::string and std::wstring. For example, TextFilt transforms the following mess:



    example.cc:21: conversion from 'double' to non-scalar type


    'map<vector<basic_string<char, string_char_traits<char>,


    __default_alloc_template<true, 0> >,


    allocator<basic_string<char, string_char_traits<char>,


    __default_alloc_template<true, 0> > > >, set<basic_string<char,


    string_char_traits<char>, _ _default_alloc_template<true, 0> >,


    less<basic_string<char, string_char_traits<char>,


    __default_alloc_template<true, 0> > >,


    allocator<basic_string<char, string_char_traits<char>,


    __default_alloc_template<true, 0> > > >,


    less<vector<basic_string<char, string_char_traits<char>,


    __default_alloc_template<true, 0> >,


    allocator<basic_string<char, string_char_traits<char>,


    __default_alloc_template<true, 0> > > > >,


    allocator<set<basic_string<char, string_char_traits<char>,


    __default_alloc_template<true, 0> >, less<basic_string<char,


    string_char_traits<char>, _ _default_alloc_template<true, 0> > >,


    allocator<basic_string<char, string_char_traits<char>,


    __default_alloc_template<true, 0> > > > > >' requested



into the much more readable:



    example.cc:21: conversion from 'double' to non-scalar type


    'map<vector<string>,set<string>>' requested



TextFilt is interesting because it is easily customizable; you can add special handling for your own types by writing "rulesets," which are simple sets of regular expression-based transformations. STLFilt is not so easily customized (unless you enjoy hacking Perl), but it includes several command line options with which you can tune how much information you see. We find these two indispensable for template metaprogramming.

  1. GCC error message reordering. Though GCC is by far our preferred compiler for metaprogram debugging, it's by no means perfect. Its biggest problem is that it prints the actual cause of an error following the entire instantiation backtrace. As a result, you often have to step through the whole backtrace before the problem becomes apparent, and the actual error is widely separated from the nearest instantiation frame. That's why the GCC error messages in this chapter are often shown with "many lines omitted...". STLFilt has two options for GCC message reordering:

    • -hdr:LD1:, which brings the actual error message to the top of the instantiation backtrace.

    • -hdr:LD2:, which is just like -hdr:LD1 but adds a copy of the final line of the backtrace (the non-template code that initiated the instantiation) just after the error message.

  2. Expression wrapping and indenting. No matter how much is done to filter irrelevant information from an error message, there's no getting around the fact that some C++ types and expressions are intrinsically complex. For example, if there were no default template arguments and typedefs to work with, getting a grip on the previous example would have required us to parse its nesting structure. STLFilt includes a -meta option that formats messages according to the conventions of this book. Even with default template argument elision and typedef substitution disabled, STLFilt can still help us see what's going on in the message:

    
    
    example.cc:21: conversion from 'double' to non-scalar type
    
    
       'map<
    
    
            vector<
    
    
                basic_string<
    
    
                    char, string_char_traits<char>
    
    
                  , __default_alloc_template<true, 0>
    
    
                >, allocator<
    
    
                    basic_string<
    
    
                        char, string_char_traits<char>
    
    
                      , __default_alloc_template<true, 0>
    
    
                    >
    
    
                >
    
    
            >, set<
    
    
                basic_string<
    
    
                    char, string_char_traits<char>
    
    
                  , __default_alloc_template<true, 0>
    
    
                >, less<
    
    
                    basic_string<
    
    
                        char, string_char_traits<char>
    
    
                      , __default_alloc_template<true, 0>
    
    
                    >
    
    
                >, allocator<
    
    
                    basic_string<
    
    
                        char, string_char_traits<char>
    
    
                      ' __default_alloc_template<true, 0>
    
    
                    >
    
    
                 >
    
    
             >, less<
    
    
                 ...12 lines omitted...
    
    
             >, allocator<
    
    
                 ...16 lines omitted...
    
    
             >
    
    
         >' requested
    
    
    

    Although the message is still huge, it has become much more readable: By scanning its first few columns we can quickly surmise that the long type is a map from vector<string> to set<string>.

Any tool can obscure a diagnostic by applying too much filtering, and STLFilt is no exception, so we encourage you to review the command line options at http://www.bdsoft.com/tools/stlfilt-opts.html and choose carefully. Fortunately, since these are external tools, you can always fall back on direct inspection of raw diagnostics.

    Team LiB
    Previous Section Next Section