Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Templates HowTo?

Reply
Thread Tools

Templates HowTo?

 
 
keith@bytebrothers.co.uk
Guest
Posts: n/a
 
      02-21-2008

I must confess I'm completely new to templates, having mainly used C++
for quite a while as 'C with Classes', but now I have an application
which seems to cry out for templates, but I just can't get my head
around how to use them in this situation. Any assistance or pointers
to other resources would be welcomed.

Let's say I have a (third party, unmodifiable) library of C functions
which provide the following interfaces:

int AAA_setup(const uint8_t* p1, int p2, struct context* p3);
int AAA_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
int AAA_done(struct context* p1);

int BBB_setup(const uint8_t* p1, int p2, struct context* p3);
int BBB_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
int BBB_done(struct context* p1);

int CCC_setup(const uint8_t* p1, int p2, struct context* p3);
int CCC_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
int CCC_done(struct context* p1);

What I want to do is provide a class wrapper for all this so that in
my C++ application I can do something like:

Work<BBB> thing;
thing.setup(&data1, val);
thing.process(&in, &out);
thing.done();

(The pointer to the context structure can obviously disappear as
private data within the class)

Now this seems from my reading to be the sort of thing that templates
are probably good at, but I can't for the life of me see how to do it,
without first creating a separate class for each of AAA, BBB, and CCC.

Can anyone enlighten me please?
 
Reply With Quote
 
 
 
 
Alf P. Steinbach
Guest
Posts: n/a
 
      02-21-2008
* http://www.velocityreviews.com/forums/(E-Mail Removed):
> I must confess I'm completely new to templates, having mainly used C++
> for quite a while as 'C with Classes', but now I have an application
> which seems to cry out for templates, but I just can't get my head
> around how to use them in this situation. Any assistance or pointers
> to other resources would be welcomed.
>
> Let's say I have a (third party, unmodifiable) library of C functions
> which provide the following interfaces:
>
> int AAA_setup(const uint8_t* p1, int p2, struct context* p3);
> int AAA_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
> int AAA_done(struct context* p1);
>
> int BBB_setup(const uint8_t* p1, int p2, struct context* p3);
> int BBB_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
> int BBB_done(struct context* p1);
>
> int CCC_setup(const uint8_t* p1, int p2, struct context* p3);
> int CCC_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
> int CCC_done(struct context* p1);
>
> What I want to do is provide a class wrapper for all this so that in
> my C++ application I can do something like:
>
> Work<BBB> thing;
> thing.setup(&data1, val);
> thing.process(&in, &out);
> thing.done();
>
> (The pointer to the context structure can obviously disappear as
> private data within the class)
>
> Now this seems from my reading to be the sort of thing that templates
> are probably good at, but I can't for the life of me see how to do it,
> without first creating a separate class for each of AAA, BBB, and CCC.
>
> Can anyone enlighten me please?


Each of group AAA, BBB and CCC essentially constitute a functor object.

class AbstractWork
{
public:
virtual ~AbstractWork() {}
virtual int operator( whatever ) = 0;
};

struct CFunctionTypes
{
typedef (*SetupFunc)
(const uint8_t* p1, int p2, struct context* p3);

typedef (*ProcessFunc)
(const uint8_t* p1, uint8_t* p2, struct context* p3);

typedef (*DoneFunc)
(struct context* p1);
};

struct AAAFunctions: CFunctionTypes
{
static SetupFunc const setup;
static ProcessFunc const process;
static DoneFunc const done;
};

CFunctionTypes::SetupFunc const AAAFunctions::setup = &AAA_setup;
CFunctionTypes:rocessFunc const AAAFunctions:rocess = &AAA_setup;
CFunctionTypes:oneFunc const AAAFunctions::done = &AAA_done;

template< class CFunctions >
class WorkWrapper
{
protected:
context myContext;

public:
WorkWrapper( uint8_t a, int b )
{
if( !CFunctions::setup( &a, b, &myContext ) )
{ throwX( "urk" ); }
}

virtual ~WorkWrapper() { CFunctions::done( &myContext ); }

virtual int operator( whatever )
{
return CFunctions:rocess( ..., ..., &myContext );
}
};

typedef WorkWrapper<AAAFcuntions> AAAWork;

Or something like that.


Cheers, & hth.,

- Alf


--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
 
 
 
keith@bytebrothers.co.uk
Guest
Posts: n/a
 
      02-21-2008
On 21 Feb, 09:20, "Alf P. Steinbach" <(E-Mail Removed)> wrote:
> * (E-Mail Removed):
> > Now this seems from my reading to be the sort of thing that templates
> > are probably good at, but I can't for the life of me see how to do it,
> > without first creating a separate class for each of AAA, BBB, and CCC.

>
> > Can anyone enlighten me please?

>
> Each of group AAA, BBB and CCC essentially constitute a functor object.


Alf, I sincerely appreciate the feedback.

Now I need to sit down in a dark room and think about what you said
until I understand And probably look up the keyword 'functor'.
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      02-21-2008
* (E-Mail Removed):
> On 21 Feb, 09:20, "Alf P. Steinbach" <(E-Mail Removed)> wrote:
>> * (E-Mail Removed):
>>> Now this seems from my reading to be the sort of thing that templates
>>> are probably good at, but I can't for the life of me see how to do it,
>>> without first creating a separate class for each of AAA, BBB, and CCC.
>>> Can anyone enlighten me please?

>> Each of group AAA, BBB and CCC essentially constitute a functor object.

>
> Alf, I sincerely appreciate the feedback.
>
> Now I need to sit down in a dark room and think about what you said
> until I understand And probably look up the keyword 'functor'.


Hm. I can see your reply, but not my posting.

So I had to check in my "Local Folders/Sent".

And discovered typo:

int operator( whatever )

should be the function call operator

int operator()( whatever )

where "whatever" means add in the arguments you need.


Cheers, & sorry for typo,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
Joe Greer
Guest
Posts: n/a
 
      02-21-2008
(E-Mail Removed) wrote in news:302ac42c-9f52-428e-ae12-
(E-Mail Removed):

>
> I must confess I'm completely new to templates, having mainly used C++
> for quite a while as 'C with Classes', but now I have an application
> which seems to cry out for templates, but I just can't get my head
> around how to use them in this situation. Any assistance or pointers
> to other resources would be welcomed.
>
> Let's say I have a (third party, unmodifiable) library of C functions
> which provide the following interfaces:
>
> int AAA_setup(const uint8_t* p1, int p2, struct context* p3);
> int AAA_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
> int AAA_done(struct context* p1);
>
> int BBB_setup(const uint8_t* p1, int p2, struct context* p3);
> int BBB_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
> int BBB_done(struct context* p1);
>
> int CCC_setup(const uint8_t* p1, int p2, struct context* p3);
> int CCC_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
> int CCC_done(struct context* p1);
>
> What I want to do is provide a class wrapper for all this so that in
> my C++ application I can do something like:
>
> Work<BBB> thing;
> thing.setup(&data1, val);
> thing.process(&in, &out);
> thing.done();
>
> (The pointer to the context structure can obviously disappear as
> private data within the class)
>
> Now this seems from my reading to be the sort of thing that templates
> are probably good at, but I can't for the life of me see how to do it,
> without first creating a separate class for each of AAA, BBB, and CCC.
>
> Can anyone enlighten me please?


Sadly, this isn't ideal for templates, because templates works on types
and it seems that what you want is token concatenation. If things are
as you have it above, then it seems that a macro would be more
appropriate to generate the wrapper classes or create a class which
contains some function pointers and initialize that. Once you have your
functions wrapped in a class, then you can use templates to apply
algorithms to those classes.

As a side note, it does seem like both templates and macros are all
about code generation. Templates do it in a completely type safe manner
and macros in a manner that doesn't obey any scoping rules, but is
potentially useful anyway. It would be nice if templates could be
enhanced with some token pasting functionality so that stuff like this
could be safely expressed. Something like

template<token P>
class Work
{
Work() { P##setup(); }
~Work() { P##_done(); }
};

Then it could be instantiated with a token and the code generated. It
seems like it should be doable. Oh well, I could dream I suppose.

For the OP, the above does NOT work. Templates work with types and some
limited PODs but not arbitrary tokens or text.

joe
 
Reply With Quote
 
keith@bytebrothers.co.uk
Guest
Posts: n/a
 
      02-21-2008
On 21 Feb, 09:20, "Alf P. Steinbach" <(E-Mail Removed)> wrote:
> * (E-Mail Removed):
> > Now this seems from my reading to be the sort of thing that templates
> > are probably good at, but I can't for the life of me see how to do it,
> > without first creating a separate class for each of AAA, BBB, and CCC.

>
> Each of group AAA, BBB and CCC essentially constitute a functor object.
>


Hi again. I'm going to try my luck one more time and ask for some
more advice on this!

Alf's suggestions upthread all worked swimmingly, but I'm left with
one thing that I can't quite work out.

The actual template is intended as a wrapper for the ciphers in
LibTomCrypt[1], and one of the things I need to do is find out the
'index' of a particular cipher by passing the cipher name as a string
to a helper function. Here's what I've got so far with Alf's help:

//--------------------- ltc.h START------------------------
#include "tomcrypt.h"

/* Our abstract base class */
class AbstractCipher
{
public:
virtual ~AbstractCipher() {}
virtual int setup (const uint8_t* key, int keylen) = 0;
virtual int ecb_encrypt (const uint8_t *ptext, uint8_t* ctext) = 0;
virtual int ecb_decrypt (const uint8_t *ctext, uint8_t* ptext) = 0;
virtual int test () = 0;
virtual int keysize (int* keysize) = 0;
virtual void done () = 0;
virtual int index () = 0;
};

/* Our functors */
struct CFunctionTypes
{
typedef int (*Setup)
(const uint_8t* key, int keylen, int rounds, symmetric_key* skey);
typedef int (*ECBencrypt)
(const uint8_t *ptext, uint8_t* ctext, symmetric_key* skey);
typedef int (*ECBdecrypt)
(const uint8_t *ctext, uint8_t* ptext, symmetric_key* skey);
typedef int (*Test)
();
typedef int (*Keysize)
(int* keysize);
typedef void (*Done)
(symmetric_key* skey);
};

/* Now specialise the functors for each cipher */
struct AESCipher:CFunctionTypes
{
static Setup const setup;
static ECBencrypt const ecb_encrypt;
static ECBdecrypt const ecb_decrypt;
static Test const test;
static Keysize const keysize;
static Done const done;
AESCipher() { register_cipher(&aes_desc); index =
find_cipher("aes");}
~AESCipher() { unregister_cipher(&aes_desc); }

int index;
};

CFunctionTypes::Setup const AESCipher::setup = &aes_setup;
CFunctionTypes::ECBencrypt const AESCipher::ecb_encrypt =
&aes_ecb_encrypt;
CFunctionTypes::ECBdecrypt const AESCipher::ecb_decrypt =
&aes_ecb_decrypt;
CFunctionTypes::Test const AESCipher::test = &aes_test;
CFunctionTypes::Keysize const AESCipher::keysize =
&aes_keysize;
CFunctionTypes:one const AESCipher::done = &aes_done;

struct TwofishCipher:CFunctionTypes
{
static Setup const setup;
static ECBencrypt const ecb_encrypt;
static ECBdecrypt const ecb_decrypt;
static Test const test;
static Keysize const keysize;
static Done const done;
TwofishCipher() { register_cipher(&twofish_desc); index =
find_cipher("twofish");}
~TwofishCipher() { unregister_cipher(&twofish_desc); }

int index;
};

CFunctionTypes::Setup const TwofishCipher::setup =
&twofish_setup;
CFunctionTypes::ECBencrypt const TwofishCipher::ecb_encrypt =
&twofish_ecb_encrypt;
CFunctionTypes::ECBdecrypt const TwofishCipher::ecb_decrypt =
&twofish_ecb_decrypt;
CFunctionTypes::Test const TwofishCipher::test =
&twofish_test;
CFunctionTypes::Keysize const TwofishCipher::keysize =
&twofish_keysize;
CFunctionTypes:one const TwofishCipher::done =
&twofish_done;

template < class CFunctions > class Cipher : public AbstractCipher
{
public:
Cipher () : skey() {}

virtual int setup (const uint_8t* key, int keylen)
{ return CFunctions::setup (key, keylen, 0, &skey); }

virtual int ecb_encrypt (const uint8_t *ptext, uint8_t* ctext)
{ return CFunctions::ecb_encrypt (ptext, ctext, &skey); }

virtual int ecb_decrypt (const uint8_t *ctext, uint8_t* ptext)
{ return CFunctions::ecb_decrypt (ctext, ptext, &skey); }

virtual int test ()
{ return CFunctions::test(); }

virtual int keysize (int* keysize)
{ return CFunctions::keysize(keysize); }

virtual int index()
{ return CFunctions::index; }

virtual ~Cipher ()
{ CFunctions::done (&skey); }

protected:
symmetric_key skey;
};

typedef Cipher < AESCipher > AES;
typedef Cipher < TwofishCipher > Twofish;

//--------------------- ltc.h END------------------------
//--------------------- x.cc BEGIN-----------------------
#include <iostream>
#include "ltc.h"

int main()
{
AES aes;
std::cerr << "AES.index() = " << aes.index();
return 0;
}

//--------------------- x.cc END-------------------------

Now you can probably see what I'm trying to do with this 'index' call;
it has to return the result of find_cipher("ciphername"). The problem
is that at compile time, I get the following error:

ltc.h: In member function 'int Cipher<CFunctions>::index() [with
CFunctions = AESCipher]':
x.cc:47: instantiated from here
ltc.h:40: error: object missing in reference to 'AESCipher::index'
ltc.h:93: error: from this location

I can't see what it is that's missing. If someone can clarify, or
even better, show me a better way to do what I'm trying to do, I'd be
grateful. Meanwhile, I'm learning a _lot_ doing this stuff!

k

1. http://libtom.org/
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      02-21-2008
* (E-Mail Removed):
> On 21 Feb, 09:20, "Alf P. Steinbach" <(E-Mail Removed)> wrote:
>> * (E-Mail Removed):
>>> Now this seems from my reading to be the sort of thing that templates
>>> are probably good at, but I can't for the life of me see how to do it,
>>> without first creating a separate class for each of AAA, BBB, and CCC.

>> Each of group AAA, BBB and CCC essentially constitute a functor object.
>>

>
> Hi again. I'm going to try my luck one more time and ask for some
> more advice on this!
>
> Alf's suggestions upthread all worked swimmingly, but I'm left with
> one thing that I can't quite work out.
>
> The actual template is intended as a wrapper for the ciphers in
> LibTomCrypt[1], and one of the things I need to do is find out the
> 'index' of a particular cipher by passing the cipher name as a string
> to a helper function. Here's what I've got so far with Alf's help:
>
> //--------------------- ltc.h START------------------------
> #include "tomcrypt.h"
>
> /* Our abstract base class */
> class AbstractCipher
> {
> public:
> virtual ~AbstractCipher() {}
> virtual int setup (const uint8_t* key, int keylen) = 0;
> virtual int ecb_encrypt (const uint8_t *ptext, uint8_t* ctext) = 0;
> virtual int ecb_decrypt (const uint8_t *ctext, uint8_t* ptext) = 0;
> virtual int test () = 0;
> virtual int keysize (int* keysize) = 0;
> virtual void done () = 0;
> virtual int index () = 0;
> };
>
> /* Our functors */
> struct CFunctionTypes
> {
> typedef int (*Setup)
> (const uint_8t* key, int keylen, int rounds, symmetric_key* skey);
> typedef int (*ECBencrypt)
> (const uint8_t *ptext, uint8_t* ctext, symmetric_key* skey);
> typedef int (*ECBdecrypt)
> (const uint8_t *ctext, uint8_t* ptext, symmetric_key* skey);
> typedef int (*Test)
> ();
> typedef int (*Keysize)
> (int* keysize);
> typedef void (*Done)
> (symmetric_key* skey);
> };
>
> /* Now specialise the functors for each cipher */
> struct AESCipher:CFunctionTypes
> {
> static Setup const setup;
> static ECBencrypt const ecb_encrypt;
> static ECBdecrypt const ecb_decrypt;
> static Test const test;
> static Keysize const keysize;
> static Done const done;
> AESCipher() { register_cipher(&aes_desc); index =
> find_cipher("aes");}
> ~AESCipher() { unregister_cipher(&aes_desc); }
>
> int index;
> };
>
> CFunctionTypes::Setup const AESCipher::setup = &aes_setup;
> CFunctionTypes::ECBencrypt const AESCipher::ecb_encrypt =
> &aes_ecb_encrypt;
> CFunctionTypes::ECBdecrypt const AESCipher::ecb_decrypt =
> &aes_ecb_decrypt;
> CFunctionTypes::Test const AESCipher::test = &aes_test;
> CFunctionTypes::Keysize const AESCipher::keysize =
> &aes_keysize;
> CFunctionTypes:one const AESCipher::done = &aes_done;
>
> struct TwofishCipher:CFunctionTypes
> {
> static Setup const setup;
> static ECBencrypt const ecb_encrypt;
> static ECBdecrypt const ecb_decrypt;
> static Test const test;
> static Keysize const keysize;
> static Done const done;
> TwofishCipher() { register_cipher(&twofish_desc); index =
> find_cipher("twofish");}
> ~TwofishCipher() { unregister_cipher(&twofish_desc); }
>
> int index;
> };
>
> CFunctionTypes::Setup const TwofishCipher::setup =
> &twofish_setup;
> CFunctionTypes::ECBencrypt const TwofishCipher::ecb_encrypt =
> &twofish_ecb_encrypt;
> CFunctionTypes::ECBdecrypt const TwofishCipher::ecb_decrypt =
> &twofish_ecb_decrypt;
> CFunctionTypes::Test const TwofishCipher::test =
> &twofish_test;
> CFunctionTypes::Keysize const TwofishCipher::keysize =
> &twofish_keysize;
> CFunctionTypes:one const TwofishCipher::done =
> &twofish_done;
>
> template < class CFunctions > class Cipher : public AbstractCipher
> {
> public:
> Cipher () : skey() {}
>
> virtual int setup (const uint_8t* key, int keylen)
> { return CFunctions::setup (key, keylen, 0, &skey); }
>
> virtual int ecb_encrypt (const uint8_t *ptext, uint8_t* ctext)
> { return CFunctions::ecb_encrypt (ptext, ctext, &skey); }
>
> virtual int ecb_decrypt (const uint8_t *ctext, uint8_t* ptext)
> { return CFunctions::ecb_decrypt (ctext, ptext, &skey); }
>
> virtual int test ()
> { return CFunctions::test(); }
>
> virtual int keysize (int* keysize)
> { return CFunctions::keysize(keysize); }
>
> virtual int index()
> { return CFunctions::index; }
>
> virtual ~Cipher ()
> { CFunctions::done (&skey); }
>
> protected:
> symmetric_key skey;
> };
>
> typedef Cipher < AESCipher > AES;
> typedef Cipher < TwofishCipher > Twofish;
>
> //--------------------- ltc.h END------------------------
> //--------------------- x.cc BEGIN-----------------------
> #include <iostream>
> #include "ltc.h"
>
> int main()
> {
> AES aes;
> std::cerr << "AES.index() = " << aes.index();
> return 0;
> }
>
> //--------------------- x.cc END-------------------------
>
> Now you can probably see what I'm trying to do with this 'index' call;
> it has to return the result of find_cipher("ciphername"). The problem
> is that at compile time, I get the following error:
>
> ltc.h: In member function 'int Cipher<CFunctions>::index() [with
> CFunctions = AESCipher]':
> x.cc:47: instantiated from here
> ltc.h:40: error: object missing in reference to 'AESCipher::index'
> ltc.h:93: error: from this location
>
> I can't see what it is that's missing. If someone can clarify, or
> even better, show me a better way to do what I'm trying to do, I'd be
> grateful. Meanwhile, I'm learning a _lot_ doing this stuff!


Well, AESCipher::index is non-static data member, that is, it only
exists in instances of AESCipher, one per instance.

To access it you'd need an AESCipher instance, but AESCipher is
currently not designed for instantiation: it's only designed as a
compile time carrier of addresses (by the way, I forgot, those function
types should probably all be 'extern "C"', but that's just a nit).

What you need seems to be singletons, and for singletons the usual way,
when you don't have other requirements, is the "Meyer's singleton"

class SingletonType
{
private:
SingletonType( SingletonType const& );
SingletonType& operator=( SingletonType const& );

public:
static SingletonType& instance()
{
static SingletonType theInstance; // Add constructor args
return theInstance;
}
};

It might also be a good idea to put all initialization calls in
constructors, and all cleanup calls in destructors. That is, no "setup"
or "cleanup" functions visible to client code at the C++ level. Of
course there may be some requirement I don't know or understand, but
usually, constructors and destructors are best for initialization and
cleanup: it automates the calls, and makes for better exception safety.


Cheers, & hth.,

- Alf

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
 
Reply With Quote
 
keith@bytebrothers.co.uk
Guest
Posts: n/a
 
      02-21-2008
On 21 Feb, 15:15, "Alf P. Steinbach" <(E-Mail Removed)> wrote:
> * (E-Mail Removed):
><snip code>
>
> > Now you can probably see what I'm trying to do with this 'index' call;
> > it has to return the result of find_cipher("ciphername"). The problem
> > is that at compile time, I get the following error:

>
> > ltc.h: In member function 'int Cipher<CFunctions>::index() [with
> > CFunctions = AESCipher]':
> > x.cc:47: instantiated from here
> > ltc.h:40: error: object missing in reference to 'AESCipher::index'
> > ltc.h:93: error: from this location

>
> > I can't see what it is that's missing. If someone can clarify, or
> > even better, show me a better way to do what I'm trying to do, I'd be
> > grateful. Meanwhile, I'm learning a _lot_ doing this stuff!

>
> Well, AESCipher::index is non-static data member, that is, it only
> exists in instances of AESCipher, one per instance.
>
> To access it you'd need an AESCipher instance, but AESCipher is
> currently not designed for instantiation: it's only designed as a
> compile time carrier of addresses (by the way, I forgot, those function
> types should probably all be 'extern "C"', but that's just a nit).


OK, I understand that.

> What you need seems to be singletons, and for singletons the usual way,
> when you don't have other requirements, is the "Meyer's singleton"
>
> class SingletonType
> {
> private:
> SingletonType( SingletonType const& );
> SingletonType& operator=( SingletonType const& );
>
> public:
> static SingletonType& instance()
> {
> static SingletonType theInstance; // Add constructor args
> return theInstance;
> }
> };


Sorry, I don't see how to apply this to what I'm doing. I think it's
getting time for more coffee... Can you expand a little for me?

> It might also be a good idea to put all initialization calls in
> constructors, and all cleanup calls in destructors. That is, no "setup"
> or "cleanup" functions visible to client code at the C++ level. Of
> course there may be some requirement I don't know or understand, but
> usually, constructors and destructors are best for initialization and
> cleanup: it automates the calls, and makes for better exception safety.


All of that is fair, and once I have the thing doing what I want, I
will probably move that stuff out of sight.

Thanks again for the help so far.
 
Reply With Quote
 
keith@bytebrothers.co.uk
Guest
Posts: n/a
 
      02-22-2008
On 21 Feb, 15:25, (E-Mail Removed) wrote:
>
> > > Now you can probably see what I'm trying to do with this 'index' call;
> > > it has to return the result of find_cipher("ciphername"). The problem
> > > is that at compile time, I get the following error:


S'ok - I cracked it!

Here's the final, working wrapper (for now). All I had to do was put
an extra static member into each specialisation, containing the name
of the cipher. Obvious after a good night's sleep! Now somebody will
tell me at least one very good reason why I shouldn't do that

//=---------------------BEGIN--------------------
#include "tomcrypt.h"

/* Our abstract base class */
class AbstractCipher
{
public:
virtual ~AbstractCipher() {}
virtual int setup (const uint8_t* key, int keylen) = 0;
virtual int ecb_encrypt (const uint8_t *ptext, uint8_t* ctext) = 0;
virtual int ecb_decrypt (const uint8_t *ctext, uint8_t* ptext) = 0;
virtual int test () = 0;
virtual int keysize (int* keysize) = 0;
virtual int index () = 0;
};

/* Our functors */
struct CFunctionTypes
{
typedef int (*Setup)
(const uint8_t* key, int keylen, int rounds, symmetric_key* skey);
typedef int (*ECBencrypt)
(const uint8_t *ptext, uint8_t* ctext, symmetric_key* skey);
typedef int (*ECBdecrypt)
(const uint8_t *ctext, uint8_t* ptext, symmetric_key* skey);
typedef int (*Test)
();
typedef int (*Keysize)
(int* keysize);
typedef void (*Done)
(symmetric_key* skey);

typedef const struct ltc_cipher_descriptor* Desc;
typedef const char* Name;
};

/* Now specialise the functors for each cipher */
struct AESCipher:CFunctionTypes
{
static Setup const setup;
static ECBencrypt const ecb_encrypt;
static ECBdecrypt const ecb_decrypt;
static Test const test;
static Keysize const keysize;
static Done const done;
static Desc const descriptor;
static Name const name;
};

CFunctionTypes::Setup const AESCipher::setup = &aes_setup;
CFunctionTypes::ECBencrypt const AESCipher::ecb_encrypt =
&aes_ecb_encrypt;
CFunctionTypes::ECBdecrypt const AESCipher::ecb_decrypt =
&aes_ecb_decrypt;
CFunctionTypes::Test const AESCipher::test = &aes_test;
CFunctionTypes::Keysize const AESCipher::keysize =
&aes_keysize;
CFunctionTypes:one const AESCipher::done = &aes_done;
CFunctionTypes:esc const AESCipher::descriptor = &aes_desc;
CFunctionTypes::Name const AESCipher::name = "aes";

struct TwofishCipher:CFunctionTypes
{
static Setup const setup;
static ECBencrypt const ecb_encrypt;
static ECBdecrypt const ecb_decrypt;
static Test const test;
static Keysize const keysize;
static Done const done;
static Desc const descriptor;
static Name const name;
};

CFunctionTypes::Setup const TwofishCipher::setup =
&twofish_setup;
CFunctionTypes::ECBencrypt const TwofishCipher::ecb_encrypt =
&twofish_ecb_encrypt;
CFunctionTypes::ECBdecrypt const TwofishCipher::ecb_decrypt =
&twofish_ecb_decrypt;
CFunctionTypes::Test const TwofishCipher::test =
&twofish_test;
CFunctionTypes::Keysize const TwofishCipher::keysize =
&twofish_keysize;
CFunctionTypes:one const TwofishCipher::done =
&twofish_done;
CFunctionTypes:esc const TwofishCipher::descriptor =
&twofish_desc;
CFunctionTypes::Name const TwofishCipher::name =
"twofish";

template < class CFunctions > class Cipher : public AbstractCipher
{
public:
Cipher () : skey()
{ register_cipher (CFunctions::descriptor); }

Cipher (const uint8_t* key, int keylen) : skey()
{ register_cipher (CFunctions::descriptor);
CFunctions::setup (key, keylen, 0, &skey);
}

virtual int setup (const uint8_t* key, int keylen)
{ return CFunctions::setup (key, keylen, 0, &skey); }

virtual int ecb_encrypt (const uint8_t *ptext, uint8_t* ctext)
{ return CFunctions::ecb_encrypt (ptext, ctext, &skey); }

virtual int ecb_decrypt (const uint8_t *ctext, uint8_t* ptext)
{ return CFunctions::ecb_decrypt (ctext, ptext, &skey); }

virtual int test ()
{ return CFunctions::test(); }

virtual int keysize (int* keysize)
{ return CFunctions::keysize(keysize); }

virtual int index ()
{ return find_cipher(CFunctions::name); }

virtual ~Cipher ()
{ CFunctions::done (&skey);
unregister_cipher (CFunctions::descriptor);
}

protected:
symmetric_key skey;
};

typedef Cipher < AESCipher > AES;
typedef Cipher < TwofishCipher > Twofish;

//=---------------------END--------------------
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      02-22-2008
On Feb 21, 9:42 am, (E-Mail Removed) wrote:
> I must confess I'm completely new to templates, having mainly
> used C++ for quite a while as 'C with Classes', but now I have
> an application which seems to cry out for templates, but I
> just can't get my head around how to use them in this
> situation. Any assistance or pointers to other resources
> would be welcomed.


> Let's say I have a (third party, unmodifiable) library of C
> functions which provide the following interfaces:


> int AAA_setup(const uint8_t* p1, int p2, struct context* p3);
> int AAA_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
> int AAA_done(struct context* p1);


> int BBB_setup(const uint8_t* p1, int p2, struct context* p3);
> int BBB_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
> int BBB_done(struct context* p1);


> int CCC_setup(const uint8_t* p1, int p2, struct context* p3);
> int CCC_process(const uint8_t* p1, uint8_t* p2, struct context* p3);
> int CCC_done(struct context* p1);


> What I want to do is provide a class wrapper for all this so
> that in my C++ application I can do something like:


> Work<BBB> thing;
> thing.setup(&data1, val);
> thing.process(&in, &out);
> thing.done();


> (The pointer to the context structure can obviously disappear
> as private data within the class)


> Now this seems from my reading to be the sort of thing that
> templates are probably good at, but I can't for the life of me
> see how to do it, without first creating a separate class for
> each of AAA, BBB, and CCC.


It's not templates you need, but macros. Something like:

class AbstractWork : private context
{
public:
virtual ~AbstractWork() {}
virtual int setup( uint8_t const* p1, int p2 ) = 0 ;
virtual int process( uint8_t const* p1, uint8_t* p2 )
= 0 ;
virtual int done() = 0 ;
} ;

#define Whatever( prefix )
class Work ## prefix : public AbstractWork
{
public:
virtual int setup( uint8_t const* p1, int p2 )
{
return prefix ## _setup( p1, p2, this ) ;
}
virtual int _process( uint8_t const* p1, uint8_t* p2 )
{
return prefix ## process( p1, p2, this ) ;
}
virtual int _done()
{
return prefix ## done( this ) ;
}
}

Whatever( AAA ) ;
Whatever( BBB ) ;
Whatever( CCC ) ;

The abstract base class may or may not be necessary at the
interface level---in this case, it's also handy for maintaining
the context structure; if you provide the necessary factory
functions in the file which defines the concrete classes, it
will also prevent the macro name from poluting the client code.
(E.g. put the definition of the abstract class in a header file,
along with the declarations of the factory functions, and just
define the macro in an implementation file which invokes it.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
how to Specializations of function Templates or Overloading Function templates with Templates ? recover C++ 2 07-25-2006 02:55 AM
Monster Templates - Question about Submitting Templates Fred HTML 1 09-26-2005 01:09 AM
Templates within templates Tom McCallum C++ 2 08-04-2004 04:44 PM
Templates templates templates JKop C++ 3 07-21-2004 11:44 AM
using templates in templates John Harrison C++ 8 07-31-2003 12:00 PM



Advertisments