Wie kann ich eine Vorlagenklasse im Namespace std weiterleiten?


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

und benutzte diese Funktion in meinem Haupt. Ich bekomme Fehler. Natürlich weiß ich, dass es mehr Vorlagenparameter für std::list( Allokator, denke ich) gibt. Aber das ist nebensächlich. Muss ich die vollständige Vorlagendeklaration einer Vorlagenklasse kennen, um sie weiterleiten zu können?

EDIT: Ich habe vorher keinen Zeiger benutzt - es war eine Referenz. Ich werde es mit dem Zeiger ausprobieren.


Und im Fall von Liste ist der zweite Parameter ein Standardparameter, derstd::allocator<T>
nakiya

2
Man kann es als Versehen betrachten, dass die STL keine Forward-Deklarations-Header enthält. Andererseits sind seine Dateien so oft enthalten, dass es wahrscheinlich keinen Nutzen für die Kompilierungszeit bringen würde ...
Matthieu M.

7
__TEST__ist eine reservierte Kennung, verwenden Sie sie nicht .
GManNickG

Antworten:


146

Das Problem ist nicht, dass Sie eine Vorlagenklasse nicht vorwärts deklarieren können. Ja, Sie müssen alle Vorlagenparameter und ihre Standardeinstellungen kennen , um sie korrekt weiterleiten zu können:

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

Aber um auch eine solche voraus Erklärung namespace stdwird ausdrücklich von der Norm verboten: Die einzige Sache , die Sie erlaubt sind zu setzen in stdeine Vorlage Spezialisierung , die gemeinhin std::lessauf einem benutzerdefinierten Typ. Jemand anderes kann bei Bedarf den entsprechenden Text zitieren.

Gerade #include <list>und machen sich keine Sorgen darüber.

Übrigens ist jeder Name, der doppelte Unterstriche enthält, für die Verwendung durch die Implementierung reserviert. Sie sollten also so etwas wie TEST_Hanstelle von verwenden __TEST__. Es wird keine Warnung oder ein Fehler generiert, aber wenn Ihr Programm mit einer implementierungsdefinierten Kennung kollidiert, kann nicht garantiert werden, dass es korrekt kompiliert oder ausgeführt wird: Es ist fehlerhaft . Ebenfalls verboten sind Namen, die unter anderem mit einem Unterstrich gefolgt von einem Großbuchstaben beginnen. Beginnen Sie Dinge im Allgemeinen nicht mit Unterstrichen, es sei denn, Sie wissen, mit welcher Magie Sie es zu tun haben.


4
Warum ist es verboten, Dinge im namespace stdÜbrigen weiterzuleiten?
Nakiya

4
Schauen Sie sich diese Antwort ( stackoverflow.com/questions/307343/… ) und die verknüpfte Newsgroup-Diskussion an.
Jon Purdy

7
Jon / Nakiya, warum nicht #pragma oncelieber die # ifdefs verwenden? Es wird heutzutage von den meisten Compilern unterstützt.
Mark Ingram

11
@ Mark: Weil es so ist #pragma, deshalb. Obwohl es eine Option ist.
Jon Purdy

2
Es gibt unzählige Duplikate dieser Frage. Suchen Sie
Jon Purdy

20

Ich habe das Problem gelöst.

Ich habe eine OSI-Ebene (Schieberegler, Ebene 2) für eine Netzwerksimulation in C ++ (Eclipse Juno) implementiert. Ich hatte Frames (Vorlage <class T>) und ihre Zustände (Zustandsmuster, Vorwärtsdeklaration).

Die Lösung lautet wie folgt:

In die *.cppDatei müssen Sie die Header-Datei aufnehmen, die Sie weiterleiten, d. H.

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;

}

Sein cpp:

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

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

Und ... eine andere Klasse.


34
Das Einfügen von using namespaceDateien in eine Header-Datei ist eine sehr schlechte Vorgehensweise, da dadurch verhindert wird, dass Personen, die diese Header-Datei verwenden, lokale Namen verwenden können, die ansonsten gültig wären. Es besiegt im Grunde den gesamten Punkt der Namespaces.
Andy Dent

10

Für die Weiterleitungsdeklaration sollte eine vollständige Liste der Vorlagenargumente angegeben sein.


-5

Es gibt eine begrenzte Alternative, die Sie verwenden können

Header:

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()) {}
[...]

nicht in realen Programmen getestet, also erwarten Sie, dass es nicht perfekt ist.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.