Thursday, July 25, 2013

Macros, templates and generics

This is a note about macros, templates and generics and how are they used to reuse code. I haven't used C/C++ since college times and I decided to write a few lines after a recent conversation with colleague about these concepts in C++ and C#.

Macros are instructions in code (like #define, #include) that are expanded at a preprocessor stage, before the actual compilation. Macros can be used to generate code by a source code search-replace manipulation.

A reason for using macros can be reusability of code. I've heard of people generating C++ functions or classes from macros. For example to generate multiple, similar classes one can define a macro, mark the fragments that can be replaced e.g. class name, base class name, method name and then use the macro invocation with arguments, and it's expanded to fully functional code.

 //An example of macro for creating classes

#include "stdafx.h"
#include <iostream>
using namespace std;

#define CREATE_CLASS(name, base_class_name, method_name) \
class name : public base_class_name \
{ \
public: \
 void method_name()\
  {\
     cout<<"You invoked: "<< #method_name << " on " << #name <<endl;\
  }\
};

class Object{};

CREATE_CLASS(Animal, Object, Feed);
CREATE_CLASS(Cat, Animal, Meow);


int _tmain(int argc, _TCHAR* argv[])
{
  Animal * a = new Animal();
  a->Feed();

  Cat * c = new Cat();
  c->Meow();
  c->Feed();

  getchar();
  return 0;
}

//OUTPUT:
//You invoked: Feed on Animal
//You invoked: Meow on Cat
//You invoked: Feed on Animal

This is a powerful way of assembling almost any code, however, C++ has also a concept of templates. There's a lot of discussion out there on why templates are usually better than macros.

Templates (C++) and generics (C#) are used to separate code to be independent of type. Templates are a compile-time concept so writing a template is indeed defining a contract that the parameter type must conform to. For example if the template invokes a constructor with arguments on parametrized type it means that the template will work with all types that have that constructor defined at the moment of compilation.

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;

//template function
template<typename TInput, typename TOutput>
void Save(TInput object)
{
  string text = object->AsString();
  TOutput * output = new TOutput(text);
  output->Flush();
}

class Console
{
  private: string _text;
  public : Console(string text)
  {
    _text = text;
  }
  public : void Flush()
  {
    cout << _text;
  }
};

class Message
{
  public: string AsString()
  {
   return "Message";
  } 
};

int _tmain()
{
  Save<Message *, Console>(new Message());

  getchar();
  return 0;
}

//OUTPUT:
//Message


C# generics retain its generic nature at runtime so all it knows about type parameter is what was specified in where clause. It wouldn't be possible to write generic method so complex as in the example above, because the where clause syntax is limited. I wouldn't say that generics are poor comparing to templates they are just different since the languages are different, C++ compiles to binary code whereas C# runs on VM.

No comments:

Post a Comment