Trying to use templated types as parameters in template specialization.

Discussion in 'C++' started by David O, Jan 5, 2007.

  1. David O

    David O Guest

    I am using the CRTP (Curiously Recurring Template Pattern) to provide a
    set of low-level functions customizable by environment. Using CRTP
    ensures that all the function have the same signatures, which becomes
    important as the interfaces grow, especially where hardware interfaces
    are involved.

    For example:

    // Feature set for the environment...
    template< class Implementation >
    class Interface
    {
    public: // Define a function and its signature...
    static void do_it( int );
    };


    // Definition for real environment...
    class Hardware
    : public Interface< Hardware >
    {
    // Nothing here as everything is in Interface<Hardware>
    // so signatures *must* match.
    };

    // Implementation of real environment...
    template<>
    void Interface< Hardware >::do_it( int i ) { /* Hack i */ }


    // Definition for test harness...
    class Simulated
    : public Interface<Simulated>
    {
    public:
    // Nothing here as everything is in Interface<Simulated>
    // so signatures *must* match.

    private:
    static int it; // Implementation of test harness.
    friend class Interface<Simulated>;
    };

    // Implementation of test harness...
    template<>
    void Interface<Simulated>::do_it( int i ) { Simulated::it = i; }

    So far, this works fine, but I want to add another level of
    templatization. Wheeler's Law applies precisely: "Any problem in
    computer science can be solved with another layer of indirection. But
    that usually will create another problem."

    My intent was to create a logging version of each implementation, to
    allow sessions to be recorded for analysis, etc...

    template< class Implementation >
    class Logged
    : public Interface< Logged<Implementation> >
    {
    public:
    // Nothing here as everything is in Interface<Simulated>
    // so signatures *must* match.

    private:
    static void log( const char *s );
    };

    // Partially specialize to implement logging of arbitrary
    implementations.
    template< class Implementation >
    void Interface< Logged<Implementation> >::do_it( int i )
    {
    Logged<Implementation>::log("doing it");
    Implementation::do_it( i );
    }

    The final specialization doesn't compile: g++ gives:
    error: invalid use of undefined type 'class
    Interface<Logged<Implementation> >'

    and Comeau gives the clearer (but no more useful):
    error: template argument list must match the parameter list

    Varying the template declaration syntax mutates the errors but hasn't
    helped. There is a simple workaround, defining the functions in the
    Logged template itself, but this returns to the original problem -
    changes to function signatures are not checked.

    Thanks,

    David O.
    David O, Jan 5, 2007
    #1
    1. Advertising

  2. David O wrote:
    > I am using the CRTP (Curiously Recurring Template Pattern) to provide
    > a set of low-level functions customizable by environment. [..]
    >
    > // Partially specialize to implement logging of arbitrary
    > implementations.
    > template< class Implementation >
    > void Interface< Logged<Implementation> >::do_it( int i )
    > {
    > Logged<Implementation>::log("doing it");
    > Implementation::do_it( i );
    > }


    You cannot partially specialise a member, it's not a template.
    You can, however, define a member for partially specialised class
    template. But you have to partially specialise the class template
    first.

    > The final specialization doesn't compile: g++ gives:
    > error: invalid use of undefined type 'class
    > Interface<Logged<Implementation> >'


    Yes, you cannot define a member of an undefined type.

    > and Comeau gives the clearer (but no more useful):
    > error: template argument list must match the parameter list


    Clearer? I am not so sure. Interface<Logged<Implementation> > has
    not beed defined. You simply are not allowed to define a member of
    an undefined class. Now, when you define a member of a [fully]
    specialised template, it causes *instantiation* (and specialisation)
    of that template. It's not the case with partial specialisation.

    > Varying the template declaration syntax mutates the errors but hasn't
    > helped. There is a simple workaround, defining the functions in the
    > Logged template itself, but this returns to the original problem -
    > changes to function signatures are not checked.


    You will have to partially specialise the template first (and while
    you're at it, define the actual member function).

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Jan 5, 2007
    #2
    1. Advertising

  3. David O

    David O Guest

    Victor Bazarov wrote:
    <snip>
    > You cannot partially specialise a member, it's not a template.
    > You can, however, define a member for partially specialised class
    > template. But you have to partially specialise the class template
    > first.


    Victor,

    Thanks for the prompt reply [delayed replying myself due to a stinking
    cold].

    I was suspecting that what I was trying top achieve was impossible.
    Other "obvious" variations, such as this (naturally) fail:

    template< class Implementation >
    class Interface< Logged<Implementation> >;

    My real question is whether it is possible to write something that
    works the way that a casual first reading of my example would seem to
    do.

    > You will have to partially specialise the template first (and while
    > you're at it, define the actual member function).


    This will achieve the functionality, but has the same problem as
    declaring the functions in the Logged template, that of ensuring all
    function signatures match - other than diligent eyeballing (or even
    macros) - which is the reason the CRTP mechanism was chosen in the
    first place.

    In the simplified example, keeping track of function signatures is
    trivial. In the real world situation, the class has an unavoidably wide
    interface (it models a hardware/OS environment) and has several
    varients and authors, so ensuring signature changes propagate correctly
    is an important issue.

    Thanks,

    David O.
    David O, Jan 10, 2007
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Marc Schellens
    Replies:
    4
    Views:
    627
    Chris Theis
    Nov 24, 2003
  2. Marijn
    Replies:
    5
    Views:
    452
    Marijn
    Feb 13, 2004
  3. case2005
    Replies:
    3
    Views:
    1,800
    Nicolas Pavlidis
    Feb 13, 2005
  4. Joseph Turian
    Replies:
    2
    Views:
    463
  5. kito
    Replies:
    2
    Views:
    413
Loading...

Share This Page