Comment transférer déclarer une classe de modèle dans l'espace de noms 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

et utilisé cette fonction dans mon principal. J'ai des erreurs. Bien sûr, je sais qu'il y a plus de paramètres de modèle pour std::list(allocator je pense). Mais ce n'est pas le sujet. Dois-je connaître la déclaration de modèle complète d'une classe de modèle pour pouvoir la transmettre?

EDIT: Je n'utilisais pas de pointeur avant - c'était une référence. Je vais l'essayer avec le pointeur.

nakiya
la source
Et dans le cas de la liste, le deuxième paramètre est un paramètre par défaut qui eststd::allocator<T>
nakiya
2
on peut considérer que c'est un oubli que la STL ne contient pas d'en-têtes de déclaration avant. En revanche, ses fichiers sont si souvent inclus que cela ne rapporterait probablement aucun avantage au moment de la compilation ...
Matthieu M.
7
__TEST__est un identifiant réservé, ne l'utilisez pas .
GManNickG
1
duplication possible du problème de déclaration avant C ++
iammilind

Réponses:

146

Le problème n'est pas que vous ne pouvez pas déclarer en avant une classe de modèle. Oui, vous devez connaître tous les paramètres du modèle et leurs valeurs par défaut pour pouvoir le déclarer correctement:

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

Mais faire même une telle déclaration directe dans namespace stdest explicitement interdit par la norme: la seule chose que vous êtes autorisé à insérer stdest une spécialisation de modèle , généralement std::lesssur un type défini par l'utilisateur. Quelqu'un d'autre peut citer le texte pertinent si nécessaire.

Juste #include <list>et ne t'inquiète pas.

Oh, d'ailleurs, tout nom contenant des doubles traits de soulignement est réservé à l'utilisation par l'implémentation, vous devriez donc utiliser quelque chose comme à la TEST_Hplace de __TEST__. Cela ne va pas générer d'avertissement ou d'erreur, mais si votre programme a un conflit avec un identifiant défini par l'implémentation, il n'est pas garanti de se compiler ou de s'exécuter correctement: il est mal formé . Sont également interdits les noms commençant par un trait de soulignement suivi d'une majuscule, entre autres. En général, ne commencez pas les choses avec des traits de soulignement à moins que vous ne sachiez à quelle magie vous avez affaire.

Jon Purdy
la source
4
Pourquoi est-il interdit de transmettre des déclarations en namespace stdbtw?
nakiya
4
Consultez cette réponse ( stackoverflow.com/questions/307343/… ) et la discussion du groupe de discussion lié.
Jon Purdy
7
Jon / Nakiya, pourquoi ne pas utiliser #pragma onceplutôt que les # ifdef. Il est pris en charge par la plupart des compilateurs de nos jours.
Mark Ingram
11
@Mark: Parce que c'est #pragma, c'est pourquoi. Bien que ce soit une option.
Jon Purdy
2
Il y a des tas de doublons de cette question. Il suffit de rechercher: stackoverflow.com/search?q=pragma+once
Jon Purdy
20

J'ai résolu ce problème.

J'étais en train d'implémenter une couche OSI (slider window, Level 2) pour une simulation de réseau en C ++ (Eclipse Juno). J'avais des cadres (modèle <class T>) et ses états (modèle d'état, déclaration avant).

La solution est la suivante:

Dans le *.cppfichier, vous devez inclure le fichier d'en-tête que vous transférez, c'est-à-dire

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;

}

Son cpp:

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

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

Et ... une autre classe.

user1638075
la source
34
En placer using namespacedans un fichier d'en-tête est une très mauvaise pratique car cela empêche quiconque utilisant ce fichier d'en-tête de pouvoir utiliser des noms locaux qui seraient autrement valides. Il bat fondamentalement le point entier des espaces de noms.
Andy Dent
10

La déclaration avant doit avoir une liste complète des arguments de modèle spécifiée.

Grozz
la source
-5

il existe une alternative limitée que vous pouvez utiliser

entête:

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

pas testé dans de vrais programmes, alors attendez-vous à ce qu'il ne soit pas parfait.

Arne
la source