[Previous]  [Up]  [Next]

CFront problems

Template semantics



CFront's template handling presents the most severe problems for the implementation of the standard C++ library. Problems relating to template instantiation will be dealt with in the next subsection. This section briefly outlines the main areas where limitations in CFront's treatment of template semantics is significant.

First, typedefs in template class scope are compiled incorrectly, for example:

    template<class T>
    class list
    {
      public:
    
        typedef T value_type;
        typedef T& reference;
        typedef list_iterator<T> iterator;
        typedef reverse_bidirectional_iterator<list_iterator<T>,
                                               T, reference>
                reverse_iterator;
    
        // etc.
    };
    
    void some_fn(list<Foo>& l)
    {
      list<Foo>::iterator i = l.begin();          // unintelligible
                                                  // error here
      list<Foo>::reverse_iterator j = l.rbegin(); // unintelligible
                                                  // error here
    
      // etc ...
    }
will not compile (the failure occurs during the C compilation phase). The workaround for container classes and their iterators is to use the iterator template classes directly, e.g.:
   typedef list_iterator<Foo> list_foo_iterator;
    
    typedef reverse_bidirectional_iterator<list_iterator<Foo>,
                                           Foo, Foo&>
            list_foo_reverse_iterator;
    
    void some_fn(list<Foo>& l)
    {
      list_foo_iterator i = l.begin();
      list_foo_reverse_iterator j = l.rbegin();
    
      // etc ...
    }

This works reasonably well in most cases, but is cumbersome.

The problem is more serious with the "traits" technique which is used quite widely throughout the library - in particular in the locales, strings and streams components, and in the container adapters. In the case of strings and streams the use of traits has simply been avoided which has forced the omission of wide character type support. Locales have not been implemented at all.

In the case of the container adapters, an additional template parameter has had to be introduced, because the adapters need to know the type of the elements of the adapted container, viz:

    template<class Container>
    class stack
    {
      public:
    
        Container::value_type const& top() const; // CFront fails
                                                  // here
        // etc.
    }
    
    stack<list<int>> stack_of_ints;
has been replaced with,
    template<class Container, class value_type>
    class stack
    {
      public:
    
        value_type const& top() const;
        // etc.
    };
    
    stack<list<int>, int> stack_of_ints;

Second, CFront cannot correctly deduce template argument types where those arguments are embedded in the declaration of a pointer to (member) function argument, e.g.:

    template<class Arg, class Result>
    inline pointer_to_unary_function<Arg, Result>
           ptr_fun(Result (*x)(Arg))
    {
      return pointer_to_unary_function<Arg, Result>(x);
    }
    
    int some_fn(char);
    
    ptr_fun(some_fn); // CFront can't deduce that Arg is char
                      // and Result is int
In this case the workaround is to use macros rather than templates, e.g.:
    #define TEMPLATE_ptr_fun_unary(Arg, Result) \
    inline pointer_to_unary_function<Arg, Result> \
           ptr_fun(Result (*x)(Arg)) \
    { \
      return pointer_to_unary_function<Arg, Result>(x); \
    }
    
    TEMPLATE_ptr_fun_unary(char, int)  // instantiation via macro
    
    int some_fn(char);
    
    ptr_fun(some_fn); // compiles OK

Third, CFront rejects declarations of an operator->() with a non-class-type return value, even where operator->() is never invoked, for example,

    template<class T>
    list_iterator
    {
      public:
    
        T* operator->();
        // etc...
    };
    
    list_iterator<int> i; // error, template argument must be
                          // of class type

Consequently operator->() has been omitted from all iterator classes. The effect of this operator for class types can be achieved thus:

    list_iterator<Foo> i = some_list.begin();
    (*i).some_foo_mfn();
which is cumbersome, but portable.

Fourth, CFront will not compile the standard destroy() template function:

    template<class T>
    inline void destroy(T* p)
    {
      p->~T();
    }
This is unfortunate, because destroy is used throughout the implementation of the container templates. The workaround is to explicitly declare a destroy() function for each class that needs one, e.g.:
    inline void destroy(Foo* p)
    {
      p->~Foo();
    }
This is inconvenient, but not particularly difficult.

Fifth, CFront will not compile member templates. Consequently any member template functions that are specified in the standard have had to be omitted. Where appropriate they have been replaced by several overloaded non-template member functions, eg.

    template<class T>
    class list
    {
      public:
    
        template<class Iterator>
        void insert(iterator const& position,
                    Iterator first, Iterator last);
        // etc...
    };
has been replaced by:
    template<class T>
    class list
    {
      public:
    
        // insert via pointers
        void insert(iterator const& position, T* first, T* last);
    
        // insert via list_iterator<T>'s
        void insert(iterator const& position,
                    iterator first, iterator last);
    };

The absence of other template idoms (template partial specialization and default template arguments), whilst not unimportant, does not have anything like the same impact as the limitations just enumerated.


 [Previous]  [Up]  [Next]