Это решение не является полностью общим, но работает для определенного типа данных:
template <class T>
class Vector {
public:
virtual void DoSomething () {
printf("general Vector template");
}
};
template<>
class Vector <Vector<int>> {
public:
void DoSomething () = delete;
};
int main(int argc, const char * argv[]) {
Vector<int> iv;
iv.DoSomething(); // OK;
Vector<Vector<int>> viv;
viv.DoSomething(); // ERROR: attempt to use a deleted function;
return 0;
}
Во-первых, оба объявления законны и в C и в C++. Однако в C, у них есть немного отличающаяся семантика. (В частности, способ, которым Вы обращаетесь к структуре позже, варьируется).
Ключевое понятие для понимания - то, что в C, структуры существуют в отдельном пространстве имен. Все встроенные типы, а также определения типов существуют в пространстве имен "по умолчанию". Таким образом, когда я ввожу int
, компилятор только проверяет это пространство имен "по умолчанию". Если я ввожу "tagMyStruct" как в Вашем примере, компилятор также только проверяет это пространство имен. Но завися, какой тип объявления Вы используете, структура не может существовать в том пространстве имен.
Структуры отличаются, и существуют в отдельном пространстве имен. Таким образом, если я делаю следующее объявление:
struct mystruct {};
Я не могу просто обратиться к нему как mystruct. Вместо этого я должен указать, что хочу mystruct, который существует в пространстве имен структуры:
void foo(struct mystruct bar); // Declare a function which takes a mystruct as its parameter
Который становится немного подробным и неловким в конечном счете. Вместо этого Вы можете определение типа это в пространство имен по умолчанию:
typedef struct mystruct mystruct; // From now on, 'mystruct' in the normal namespace is an alias for 'mystruct' in the struct namespace
и теперь, моя функция может быть объявлена простым способом:
void foo(mystruct bar);
Таким образом, Ваш первый пример просто объединяет эти два шага вместе: Объявите структуру и поместите псевдоним в регулярное пространство имен. И конечно, так как мы - typedeffing это так или иначе, нам не нужно "исходное" имя, таким образом, мы можем сделать структуру анонимной. Таким образом, после Вашего объявления
typedef struct { int i; double d; } tagMyStruct;
у нас есть структура без имени, которое было typedef'ed к 'tagMyStruct' в пространстве имен по умолчанию.
Это - то, как C рассматривает его. Оба типа объявлений допустимы, но каждый не создает псевдоним в пространстве имен "по умолчанию", таким образом, необходимо использовать ключевое слово структуры каждый раз, когда Вы обращаетесь к типу.
В C++ не существует отдельное пространство имен структуры, таким образом, они имеют в виду то же самое. (но более короткая версия предпочтена).
Редактирование Только, чтобы быть ясным, нет, C не имеет пространств имен. Не в обычном смысле. C просто помещает идентификаторы в одно из двух предопределенных пространств имен. Названия структур (и перечисления, как я вспоминаю) помещаются в одно и все другие идентификаторы в другом. Технически, это пространства имен, потому что они - отдельные "контейнеры", в которых имена помещаются для предотвращения конфликтов, но они, конечно, не, пространства имен в C++/C# распознаются.
В C, если необходимо было записать
struct MyStruct { int i; double d; };
каждый раз, когда Вы хотели сослаться на тот тип, необходимо будет указать, что Вы говорили о структуре:
struct MyStruct instanceOfMyStruct;
struct MyStruct *ptrToMyStruct;
С версией определения типа:
typedef struct { int i; double d; } tagMyStruct;
только необходимо записать:
tagMyStruct instanceOfMyStruct;
tagMyStruct *ptrToMyStruct;
Другое большое преимущество с typedef'd версией состоит в том, что можно отослать к структуре тот же путь и в C и в C++, тогда как во второй версии они отнесены в по-другому в C, чем в C++.
Это - просто стенография.
Во втором экземпляре для объявления структуры Вы сделали бы так с:
struct MyStruct a;
В первом варианте Вы сделали бы так с:
tagMyStruct a;
Второй вариант также существует в C.
Вы используете первый вариант каждый раз, когда Вы хотите назвать свой тип, например:
tagEnum myFunc(tagMyStruct * myArg);
Первый может быть неудобным в C++, поскольку Вы не можете передать, объявляют это в заголовочном файле.