Pourquoi pas une déclaration anticipée être utilisé pour un std::vector?
Si je créer une classe comme ceci:
//B.h
#ifndef _B_H_
#define _B_H_
class B
{
private:
int x;
int y;
};
#endif //_B_H_
et de l'utiliser comme ceci:
//main.cpp
#include <iostream>
#include <vector>
class B; //Forward declaration.
class A
{
public:
A() {
std::cout << v.size() << std::endl;
}
private:
std::vector<B> v;
};
int main()
{
A a;
}
Le compilateur échoue lors de la compilation de main.cpp
. Maintenant la solution je sais, c'est pour #include "B.h"
, mais je suis curieux de savoir pourquoi il échoue. Ni g++
ou cl
's messages d'erreur ont été très éclairante à ce sujet.
- Remarque vous pouvez passer une
vector<T>
dans une fonction avec seulement avant type déclaréT
si vous passez comme unvector<T>&
(mais pasvector<T>
parce que nécessiterait une opération de copie)
Vous devez vous connecter pour publier un commentaire.
Le compilateur doit savoir comment grand "B" est avant il peut générer de la disposition appropriée de l'information. Si au lieu de cela, vous avez dit
std::vector<B*>
, alors le compilateur n'a pas besoin de savoir comment big B est parce qu'il sait comment grand un pointeur.vector<T>
probablement que contient un pointeur sur T, donc je suis en désaccord avec Curt réponse. La mise en page devector<B>
peut être connu sans le savoir la définition deB
, mais depuisvector
est un modèle, de toutes ses fonctions de membre doit être instancié pour chaque modèle argument: on ne peut pas séparer leurs déclarations de leurs implémentations. Étant donné que certaines de ces fonctions de membre devraT
définition, il doit être d'un type complètes pour être utilisé dans unvector
. Le problème est dû à des fonctions de membre en cours de définition en ligne, de ne pasvector<B>
's layout en fonctionB
's layout.En fait, votre exemple serait de construire si Un constructeur ont été mis en œuvre dans une unité de compilation que connaît le type de B.
Un std::vector exemple, a une taille fixe, peu importe ce que T est, puisqu'il contient, comme d'autres ont dit avant, seulement un pointeur vers T. Mais le vecteur du constructeur dépend du type de béton. Votre exemple ne compile pas car A() essaie d'appeler le vecteur de ctor, qui ne peut pas être produite sans le savoir B. Voici ce que serait le travail:
Une déclaration:
Une mise en œuvre:
Maintenant un utilisateur d'Un besoin de savoir seulement, pas de B:
error C2036: 'B *': unknown size
La raison n'est pas tout à fait clair, mais il se peut que VS2015 fait plus tôt l'instanciation d'un modèle devector<T>
que GCC/Clang.gcc
et compile très bien.Pour instancier Un::v, le compilateur a besoin de connaître le type concret de B.
Si vous essayez de réduire au minimum la quantité de #inclus bagages pour améliorer les temps de compilation, il y a deux choses que vous pouvez faire, qui sont vraiment les variations de l'autre:
Il est plus que juste la taille de B qui est nécessaire. Les compilateurs modernes auront fantaisie pour accélérer vecteur de copies à l'aide de memcpy, si possible, par exemple. Ceci est généralement réalisé par partiellement spécialisé sur le POD-ness le type de l'élément. Vous ne pouvez pas dire si B est un module à partir d'une déclaration anticipée.
Comme fyzix dit, la raison de votre déclaration anticipée n'est pas le travail, c'est à cause de votre constructeur inline. Même un constructeur vide peut contenir beaucoup de code, comme la construction de la non-POD membres. Dans votre cas, vous avez un vecteur d'initialisation, qui vous ne pouvez pas faire sans définir son type de modèle complètement.
Il en va de même pour les destructeurs. Le vecteur doit le type de modèle de définition de dire ce destructeur à l'appel lors de la destruction d'instances qu'il détient.
Pour se débarrasser de ce problème, il suffit de ne pas inline constructeurs et destructeurs. Définir séparément quelque part après B est complètement défini.
Pour plus d'informations,
http://www.chromium.org/developers/coding-style/cpp-dos-and-donts
Ce n'est pas grave si vous utilisez un vecteur ou juste essayer d'instancier un B. Instanciation nécessite la définition d'un objet.
Homme, vous êtes l'instanciation
std::vector
avec un type incomplète. Ne touchez pas à la déclaration anticipée, il suffit de déplacer le constructeur de la définition de la.cpp
fichier.La raison pour laquelle vous ne pouvez pas utiliser une déclaration anticipée est parce que la taille de B est inconnu.
Il n'y a aucune raison dans votre exemple que vous ne pouvez pas inclure de B. h à l'intérieur de A. h, de sorte que ce problème vous êtes vraiment essayer de résoudre?
Edit: Il y a une autre façon de résoudre ce problème, trop: stop à l'aide de C/C++! C'est tellement années 1970... 😉