Why is this C ++ class not equivalent to this pattern?

Can someone explain to me why the following works:

template<class T> class MyTemplateClass {
public:
    T * ptr;
};

int main(int argc, char** argv) {
    MyTemplateClass<double[5]> a;
    a.ptr = new double[10][5];
    a.ptr[2][3] = 7;
    printf("%g\n", a.ptr[2][3]);
    return 0;
}

      

But this is not the case:

class MyClass {
public:
    double[5] * ptr;
    // double(*ptr)[5]; // This would work
};

int main(int argc, char** argv) {
    MyClass a;
    a.ptr = new double[10][5];
    a.ptr[2][3] = 7;
    printf("%g\n", a.ptr[2][3]);
    return 0;
}

      

Obviously there is more to template creation than just textual replacement with template arguments - is there a simple explanation for this magic?

For the latter, the compiler (g ++ 4.1.2) spits out the following error:

test.cxx:13: error: expected unqualified-id before '[' token

      

If line 13 is a string double[5] * ptr;

.

The question is not:

"Why isn't MyClass in the example? - because C ++ doesn't allow Java style array declarations ;-)".

But there is:

"Why does the MyTemplateClass example succeed?"

0


a source to share


3 answers


The difference lies in the C ++ grammar. A simple declaration is formed as follows:

declaration-specifier-seq init-declarator-list

      

Where declare-specifier-seq is a sequence of declaration specifiers:

simple-type-specifier: int, bool, unsigned, typedef-name, class-name ...
class-specifiers: class X { ... }
type-qualifier: const, volatile
function-specifier: inline, virtual, ... 
storage-class-specifier: extern, static, ...
typedef

      

You get the idea. And init-declarator-list is a list of declarators, with an optional initializer for each:

a
*a
a[N]
a()
&a = someObj

      

So a complete simple declaration might look like this, contains 3 declarations:



int a, &b = a, c[3] = { 1, 2, 3 };

      

Class members have special rules to account for the different contexts in which they appear, but they are very similar. Now you can do

typedef int A[3];
A *a;

      

Since the former uses the typedef specifier and then the simple-type-specifier and then the "a [N]" type declarator. The second declaration then uses the typedef-name "A" (simple type-specifier) ​​and then the type declarator "* a". However, you certainly cannot do

int[3] * a;

      

Because "int [3]" is not a valid seq-qualifier as shown above.

And now, of course, the template is not like a replacement for a macro. A template type parameter is, of course, treated like any other type name, which is interpreted as just the type it names and may appear where a simple type specifier may appear. Some people in C # tend to say that C ++ templates are "just like macros", but of course they are not :)

+9


a source


template<class T> MyTemplateClass {
    ...
}

      

closer to



template<class T> MyTemplateClass {
    typedef {actual type} T;
    ...
}

      

than simple text substitution.

+3


a source


There is a difference between using a pointer or an array of pointers. You need to allocate memory for each element of your array before you are going to use it, and yes, you have a typo in your second example where you did not define a template.

0


a source







All Articles