4

I have the following code, which is vital to understand a class I'm working on translating from visual c++ to c#

typedef Rect<double, 2> Rect2;

I simply can't understand what does it mean. I have come to understand that vc++ uses 'stl' or 'std' and a 'vector' class, which is similar to c# list or arraylist, but the syntax up completely eludes me.

By the way, Rect definition is written like this

template<class Real, int Dim>
class Rect {

Rect is a class in one of the vc++ project files, but I can't understand what's the point of this typedef. It's 200+ lines so here's the declaration start

template<class Real, int Dim>
class Rect {
public:

typedef Vector<Real, Dim> Vec;
typedef Rect<Real, Dim> Self;
typedef _RectPrivate::RectOp<Dim> RO;

Rect() : empty(true) {}
Rect(const Vec &vec) : empty(false), lo(vec), hi(vec) {}
Rect(const Vec &inLo, const Vec &inHi) : lo(inLo), hi(inHi) { markEmpty(); }
Rect(const Rect &inRect) : empty(inRect.empty), lo(inRect.lo), hi(inRect.hi) {}
template<class R> Rect(const Rect<R, Dim> &inRect) : empty(inRect.empty), lo(inRect.lo), hi(inRect.hi) {}

Any help appreciated.

roamcel
  • 645
  • 1
  • 8
  • 17

2 Answers2

7

Based on your comments to the other answer, the problem you're facing is that you do not understand what C++ templates are. They are actually quite different from C# generics. They are conceptually similar, and syntactically similar, but their actual implementation is very different.

The easiest way to think about a template in C++ is as a "search and replace" mechanism. When you see

typedef Rect<double, 2> Rect2;

That means go find the template class for Rect that takes two template arguments. Here it is:

template<class Real, int Dim>
class Rect {

OK, so "double" corresponds to "class Real" and "2" corresponds to "int Dim". Sure enough, double is a type and 2 is an int, so that works properly. Now go through the template class and replace all instances of "Real" with "double" and "Dim" with 2. The result is:

typedef /* now we start replacing double for Real and 2 for Dim */ 
class Rect {
public:
typedef Vector<double, double> Vec;
typedef Rect<double, 2> Self;
typedef _RectPrivate::RectOp<2> RO;
Rect() : empty(true) {}
Rect(const Vec &vec) : empty(false), lo(vec), hi(vec) {}
...
} Rect2;

Notice that the result of search-and-replace on the template itself both defines and uses more templates, which have to themselves be search-and-replaced to construct them. We'd do a search-and-replace on the Vector template, and so on.

The "typedef" just means "when I say Rect2 I mean Rect<double, 2>". The same way in C# you can say

using MyStringList = System.Collections.Generic.List<string>;

There are many differences between C# generics and C++ templates. The obvious difference here is that C# generics can only be parameterized with types, never with values as is done in this template. Another difference is that C++ templates are fully constructed at compile time, and need only be legally constructable with the actual arguments given in the program. Whereas C# generics must be constructable with any arguments that meet the stated constraints, and the new code generation does not happen until runtime.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • "Whereas C# generics must be constructable with any arguments that meet the stated constraints, and the new code generation does not happen until runtime." Could you explain what does it mean? Sounds like a performance penalty while using generics, but it's not, is it? – Lukasz Madon Oct 11 '11 at 15:12
  • 1
    That means that the JIT will create a unique type for each generic type based on its type parameters, then cache it for further use. This is why SomeClass and SomeClass are two separate types at runtime. – Chris Hannon Oct 11 '11 at 16:24
  • @lukas, what kind of performance penalty are you talking about? If you have one generic class in C# and use it with N different sets of type parameters, then the native code for it might have to be generated N times during run time. But this happens just once during the whole execution of program, so the actual penalty is tiny. And templates in C++/CLI have the same penalty. I guess I probably misunderstood what penalty are you talking about. – svick Oct 11 '11 at 17:09
  • Thanks for the thorough explanation. It makes sense now. – roamcel Oct 11 '11 at 17:18
  • 3
    @lukas: There is a performance and space penalty for using generics at runtime because the *first* time a generic is used it must be codegenned at runtime. However, the codegen only happens once per appdomain per construction. Moreover, two constructions that are both constructed with reference types for the type arguments only incur the penalty *once*. So when you make the first `List` you get `List` for free. Also, by using generics constructed with value types you get a first-call jit cost but eliminate an every-call boxing cost. – Eric Lippert Oct 11 '11 at 17:58
4

it creates an alternative name for (alias) Rect<double, 2>. Rect is a class template, which is somewhat comparable to Generics in C#. So Rect2 is Rect with Real=double and Dim=2.

smerlin
  • 6,446
  • 3
  • 35
  • 58
  • 1
    Somewhat comparable, except that generics can't do what this template does. :) – jalf Oct 11 '11 at 07:51
  • In C# there is something similar. It's a little used variant of the `using` statement. For example, if you place `using xxx = System.Web.HttpContext;` at the top of the file (next to other `using`s there), then below you can use `xxx` as a synonym to `System.Web.HttpContext`. – Vilx- Oct 11 '11 at 07:52
  • Thanks. So I think I'm starting to understand: this **typedef Rect Rect2;** is not an instance, but an actual type? Ultimately then, what does **template** mean, please? – roamcel Oct 11 '11 at 08:12
  • @roamcel What's the "Real" class for – Tim Oct 11 '11 at 09:34
  • Sadly there's no class or type definition for Real in the code. I'm at a loss. – roamcel Oct 11 '11 at 14:17
  • @jalf: Yes of course they cant, indeed i should have been including that in my answer. On of the major drawbacks, which could lead to problems in this case aswell, is the missing possibility, to do something like `where T: number-type` in C#. So you cant easily use arithmethic operators on variables of type T. See this question: http://stackoverflow.com/questions/32664/c-generic-constraint-for-only-integers – smerlin Oct 11 '11 at 18:53