Trying to use templated types as parameters in template specialization.

D

David O

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.
 
V

Victor Bazarov

David said:
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
 
D

David O

Victor Bazarov wrote:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top