Jak przekazać dalej zadeklarować klasę szablonu w przestrzeni nazw std?

132
#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

i użyłem tej funkcji w moim pliku main. Otrzymuję błędy. Oczywiście wiem, że istnieje więcej parametrów szablonu std::list(myślę, że alokator). Ale to nie ma znaczenia. Czy muszę znać pełną deklarację szablonu klasy szablonu, aby móc ją dalej zadeklarować?

EDYCJA: wcześniej nie używałem wskaźnika - to było odniesienie. Wypróbuję to za pomocą wskaźnika.

nakiya
źródło
A w przypadku listy drugim parametrem jest parametr domyślny czylistd::allocator<T>
nakiya
2
można uznać za przeoczenie fakt, że STL nie zawiera nagłówków deklaracji wysyłkowej. Z drugiej strony, jego pliki są tak często dołączane, że prawdopodobnie nie przyniosłoby to żadnych korzyści w czasie kompilacji ...
Matthieu M.,
7
__TEST__jest zastrzeżonym identyfikatorem, nie używaj go .
GManNickG
1
możliwy duplikat problemu z deklaracją przekazywania C ++
iammilind

Odpowiedzi:

147

Problem nie polega na tym, że nie można przesłać dalej deklaracji klasy szablonu. Tak, musisz znać wszystkie parametry szablonu i ich wartości domyślne, aby móc poprawnie zadeklarować je dalej:

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

Ale nawet taka deklaracja forward namespace stdjest wyraźnie zabroniona przez standard: jedyną rzeczą, którą możesz wprowadzić, stdjest specjalizacja szablonu , zwykle std::lessw typie zdefiniowanym przez użytkownika. W razie potrzeby ktoś inny może zacytować odpowiedni tekst.

Po prostu #include <list>i nie martw się o to.

Aha, nawiasem mówiąc, każda nazwa zawierająca podwójne podkreślenie jest zarezerwowana do użytku przez implementację, więc powinieneś użyć czegoś takiego jak TEST_Hzamiast __TEST__. Nie wygeneruje ostrzeżenia ani błędu, ale jeśli w programie występuje konflikt z identyfikatorem zdefiniowanym w ramach implementacji, nie ma gwarancji, że skompiluje się lub uruchomi się poprawnie: jest źle sformułowany . Zabronione są również nazwy zaczynające się między innymi od podkreślenia, po którym następuje duża litera. Ogólnie rzecz biorąc, nie zaczynaj rzeczy od podkreślenia, chyba że wiesz, z jaką magią masz do czynienia.

Jon Purdy
źródło
4
Dlaczego przy namespace stdokazji zgłaszanie rzeczy dalej jest zabronione ?
nakiya
4
Zapoznaj się z tą odpowiedzią ( stackoverflow.com/questions/307343/… ) i połączoną dyskusją na grupie dyskusyjnej.
Jon Purdy,
7
Jon / Nakiya, dlaczego nie użyć #pragma oncezamiast # ifdef. Obecnie jest obsługiwany przez większość kompilatorów.
Mark Ingram
11
@Mark: Ponieważ tak #pragma, właśnie dlatego. Chociaż jest to opcja.
Jon Purdy,
2
Istnieje wiele kopii tego pytania. Po prostu wyszukaj: stackoverflow.com/search?q=pragma+once
Jon Purdy
20

Rozwiązałem ten problem.

Wdrażałem warstwę OSI (okno suwaka, poziom 2) do symulacji sieci w C ++ (Eclipse Juno). Miałem ramki (szablon <class T>) i jego stany (wzorzec stanu, deklaracja forward).

Rozwiązanie jest następujące:

W *.cpppliku musisz dołączyć plik nagłówkowy, który przekazujesz dalej, tj

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;

}

Jego CPP:

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

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

I ... inna klasa.

user1638075
źródło
34
Umieszczenie któregokolwiek using namespacez plików nagłówkowych jest bardzo złą praktyką, ponieważ uniemożliwia każdemu używającemu tego pliku nagłówkowego możliwości używania lokalnych nazw, które w innym przypadku byłyby prawidłowe. Zasadniczo pokonuje cały punkt przestrzeni nazw.
Andy Dent
10

Deklaracja forward powinna mieć określoną pełną listę argumentów szablonu.

Grozz
źródło
-5

istnieje ograniczona alternatywa, z której możesz skorzystać

nagłówek:

class std_int_vector;

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

cpp:

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

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

nie był testowany w prawdziwych programach, więc spodziewaj się, że nie będzie doskonały.

Arne
źródło