Как переслать объявление класса шаблона в пространстве имен std?


131
#ifndef __TEST__
#define __TEST__

namespace std
{
    template<typename T>
    class list;
}

template<typename T>
void Pop(std::list<T> * l)
{
    while(!l->empty())
        l->pop();
}

#endif

и использовал эту функцию в моем main. Я получаю ошибки. Конечно, я знаю, что есть еще параметры шаблона для std::list(мне кажется, распределителя). Но это не относится к делу. Должен ли я знать полное объявление шаблона класса шаблона, чтобы пересылать его объявление?

РЕДАКТИРОВАТЬ: Я раньше не использовал указатель - это была ссылка. Попробую с указателем.


А в случае списка второй параметр является параметром по умолчанию, который равенstd::allocator<T>
накия

2
то, что STL не содержит заголовков прямого объявления, можно считать недосмотром. С другой стороны, его файлы так часто включаются, что это, вероятно, не принесет никакой пользы от времени компиляции ...
Матье М.

7
__TEST__зарезервированный идентификатор, не используйте его .
GManNickG

Ответы:


146

Проблема не в том, что вы не можете напрямую объявить шаблонный класс. Да, вам нужно знать все параметры шаблона и их значения по умолчанию, чтобы иметь возможность правильно пересылать-объявить его:

namespace std {
  template<class T, class Allocator = std::allocator<T>>
  class list;
}

Но делать даже такое предварительное объявление namespace stdявно запрещено стандартом: единственное, что вам разрешено, std- это специализация шаблона , обычно std::lessдля определяемого пользователем типа. При необходимости кто-то другой может процитировать соответствующий текст.

Просто #include <list>и не беспокойся об этом.

Кстати, любое имя, содержащее двойное подчеркивание, зарезервировано для использования реализацией, поэтому вы должны использовать что-то вроде TEST_Hвместо __TEST__. Он не будет генерировать предупреждение или ошибку, но если ваша программа имеет конфликт с идентификатором, определяемым реализацией, то она не гарантирует правильную компиляцию или выполнение: она плохо сформирована . Также запрещены имена, начинающиеся с символа подчеркивания, за которым следует заглавная буква. В общем, не начинайте с подчеркивания, если не знаете, с какой магией имеете дело.


4
Почему запрещено пересылать namespace stdдекларацию кстати?
Накия 07

4
Посмотрите этот ответ ( stackoverflow.com/questions/307343/… ) и обсуждение в связанной группе новостей.
Джон Парди,

7
Джон / Накия, почему бы не использовать #pragma onceвместо # ifdef. В наши дни он поддерживается большинством компиляторов.
Марк Ингрэм

11
@Mark: Потому что #pragmaэто вот почему. Хотя это вариант.
Джон Парди

2
Есть множество дубликатов этого вопроса. Просто ищите: stackoverflow.com/search?q=pragma+once
Джон Парди,

20

Я решил эту проблему.

Я реализовал уровень OSI (окно слайдера, уровень 2) для моделирования сети на C ++ (Eclipse Juno). У меня были фреймы (шаблон <class T>) и его состояния (шаблон состояния, предварительное объявление).

Решение заключается в следующем:

В *.cppфайл вы должны включить файл заголовка, который вы пересылаете, т.е.

ifndef STATE_H_
#define STATE_H_
#include <stdlib.h>
#include "Frame.h"

template <class T>
class LinkFrame;

using namespace std;

template <class T>
class State {

  protected:
    LinkFrame<int> *myFrame;

}

Его cpp:

#include "State.h"
#include "Frame.h"
#include  "LinkFrame.h"

template <class T>
bool State<T>::replace(Frame<T> *f){

И ... еще один класс.


34
Помещение любого имени using namespaceв файл заголовка - очень плохая практика, потому что это не позволяет любому, кто использует этот файл заголовка, использовать локальные имена, которые в противном случае были бы действительными. Это в основном поражает всю точку пространств имен.
Энди Дент

10

В форвардном объявлении должен быть указан полный список аргументов шаблона.


-5

есть ограниченная альтернатива, которую вы можете использовать

заголовок:

class std_int_vector;

class A{
    std_int_vector* vector;
public:
    A();
    virtual ~A();
};

каст:

#include "header.h"
#include <vector>
class std_int_vector: public std::vectror<int> {}

A::A() : vector(new std_int_vector()) {}
[...]

не тестировался в реальных программах, поэтому ожидайте, что он не идеален.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.