Почему этот класс C ++ не эквивалентен этому шаблону? - PullRequest
0 голосов
/ 19 мая 2009

Может кто-нибудь объяснить мне, почему работает следующее:

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;
}

Но это не так:

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;
}

Очевидно, что создание экземпляра шаблона - это не просто текстовая замена аргументами шаблона - есть ли простое объяснение этой магии?

Для последнего компилятор (g ++ 4.1.2) выдает следующую ошибку:

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

Где строка 13 - это строка double[5] * ptr;.

Вопрос не в следующем:

«Почему не удается пример MyClass? - потому что C ++ не допускает объявления массивов в стиле Java ;-)».

Но есть:

«Почему пример MyTemplateClass успешен?»

Ответы [ 3 ]

9 голосов
/ 19 мая 2009

Разница заключается в грамматике C ++. Простая декларация формируется так:

declaration-specifier-seq init-declarator-list

Где объявление-спецификатор-seq представляет собой последовательность спецификаторов объявления:

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

Вы поняли идею. И список инициаторов объявлений - это список деклараторов с необязательным инициализатором для каждого:

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

Таким образом, полное простое объявление может выглядеть следующим образом, содержащее 3 объявления:

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

Члены класса имеют специальные правила для учета различного контекста, в котором они появляются, но они очень похожи. Теперь вы можете сделать

typedef int A[3];
A *a;

Так как первый использует спецификатор typedef, а затем простой-type-спецификатор, а затем декларатор типа "a [N]". Во втором объявлении затем используется typedef-name «A» (простой-type-спецификатор), а затем декларатор типа «* a». Тем не менее, вы, конечно, не можете сделать

int[3] * a;

Так как "int [3]" не является допустимым описателем-спецификатора объявления, как показано выше.

И теперь, конечно, шаблон не , как подстановка текста макроса. Конечно, параметр типа шаблона обрабатывается как любое другое имя типа, которое интерпретируется как просто тип, который он называет, и может появляться там, где может появиться спецификатор простого типа. Некоторые люди на C # говорят, что шаблоны C ++ «просто как макросы», но, конечно, это не так:)

3 голосов
/ 19 мая 2009
template<class T> MyTemplateClass {
    ...
}

ближе к

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

, чем к простой подстановке текста.

0 голосов
/ 19 мая 2009

Существует разница между использованием указателя или массива указателей. Необходимо выделить память для каждого элемента вашего массива, прежде чем вы собираетесь его использовать, и да, у вас есть опечатка во втором примере, в котором вы не определили шаблон.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...