![]() |
Templates HowTo?
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? |
Re: Templates HowTo?
* keith@bytebrothers.co.uk:
> 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::ProcessFunc const AAAFunctions::process = &AAA_setup; CFunctionTypes::DoneFunc 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::process( ..., ..., &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? |
Re: Templates HowTo?
On 21 Feb, 09:20, "Alf P. Steinbach" <al...@start.no> wrote:
> * ke...@bytebrothers.co.uk: > > 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'. |
Re: Templates HowTo?
* keith@bytebrothers.co.uk:
> On 21 Feb, 09:20, "Alf P. Steinbach" <al...@start.no> wrote: >> * ke...@bytebrothers.co.uk: >>> 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? |
Re: Templates HowTo?
keith@bytebrothers.co.uk wrote in news:302ac42c-9f52-428e-ae12-
d600560c2d6e@72g2000hsu.googlegroups.com: > > 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 |
Re: Templates HowTo?
On 21 Feb, 09:20, "Alf P. Steinbach" <al...@start.no> wrote:
> * ke...@bytebrothers.co.uk: > > 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::Done 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::Done 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/ |
Re: Templates HowTo?
* keith@bytebrothers.co.uk:
> On 21 Feb, 09:20, "Alf P. Steinbach" <al...@start.no> wrote: >> * ke...@bytebrothers.co.uk: >>> 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::Done 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::Done 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? |
Re: Templates HowTo?
On 21 Feb, 15:15, "Alf P. Steinbach" <al...@start.no> wrote:
> * ke...@bytebrothers.co.uk: ><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. |
Re: Templates HowTo?
On 21 Feb, 15:25, ke...@bytebrothers.co.uk 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::Done const AESCipher::done = &aes_done; CFunctionTypes::Desc 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::Done const TwofishCipher::done = &twofish_done; CFunctionTypes::Desc 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-------------------- |
Re: Templates HowTo?
On Feb 21, 9:42 am, ke...@bytebrothers.co.uk 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:james.kanze@gmail.com 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 |
| All times are GMT. The time now is 12:22 PM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.