Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien
Toon posts:

[C++] VC6 => 2005 conversie probl. met STL mappen

Pagina: 1
Acties:

Verwijderd

Topicstarter
Hallo allen,

Ik zit momenteel even met mijn handen in het haar...
We hebben een VC++ 6.0 project welke we willen bewerken en bouwen vanaf VS2005 (C++). Helaas loop ik hierbij in een vervelend probleem in de hoek van STL mappen. Ik heb geen kaas gegeten van STL (het is 3rd party code), dus ik hoop dat jullie me iets vooruit kunnen helpen.

Eerst hieronder de bewuste code (header-file), die als basis dient voor andere map-classes. Hier gaat de compiler de mist in gaat tijdens compileren. Ik heb de code iets gestript om het overzichtelijk te houden.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// ...
// File       : SynchronizedMap.h
//
// Description: Encapsulates the functionalities of a synchronized map container of objects.
//
// Decisions
//
// History    :
// ....
#ifndef _C_SYNCHRONIZED_MAP_H
#define _C_SYNCHRONIZED_MAP_H

#include "HmpMutex.h"
#include <map>

template <typename keyT, typename objT>

class CSynchronizedMap  
{
public:
  
 // ... removed some methods to keep this small

   /**
   * Function : LookupObject
   * 
   * Abstract : Lookup in the map the object associated with a certain key. 
   *
   * Exception: -
   *
   * Remarks  : If an object was found the return value is true and the rObject is valid.
     *            If no object is found the return value is false and rObject is invalid.
   */
  bool LookupObject ( keyT key, objT& rObject )
  {
    std::map < keyT, objT >::iterator matchedObject;
        bool bFound = false;

    if ( m_Mutex.Lock () == true )
    {
      // check if the map is not empty
      if ( !m_ObjectsMap.empty () )
      {
        // lookup
        matchedObject = m_ObjectsMap.find ( key );

        if ( matchedObject != m_ObjectsMap.end () )
        {
          // if the key matched an item get the address of that item
          rObject = (*matchedObject).second;
                    bFound = true;
        }   
      } 
      m_Mutex.Unlock ();
    }   
    return bFound;  
  }

 // ... removed some methods to keep this small

  /**
   * Function : HasNext
   * 
   * Abstract : Returns true if there is a next element
   *              starting from the current position of 
   *              the class iterator 
   *
   * Exception: -
   *
   * Remarks  : 
   */
  bool  HasNext ()
  {
    bool    bResult = false;
    if ( m_Mutex.Lock () == true )
    {
      // If the map is empty then 
      
      if ( m_Iterator != m_ObjectsMap.end() )
      {
        m_Iterator++ ;
        if ( m_Iterator != m_ObjectsMap.end ())
        {
          bResult = true;
        }
        m_Iterator-- ;
      }
      
      m_Mutex.Unlock ();
    }
    return bResult;
  }
 
  /**
   * Function : GetNext
   * 
   * Abstract : Returns the object associated with
   *              the next key  from the map, considering
   *              the current position of the maps' iterator.
   *
   * Exception: -
   *
   * Remarks  : 
   */
  bool  GetNext ( objT& rObject  )
  {
    bool    bResult = false;
    
    if ( m_Mutex.Lock () == true )
    {
      if ( HasNext () )
      {
        m_Iterator++;
        rObject = ( *m_Iterator ).second;
        bResult = true;
      }
      m_Mutex.Unlock ();
    }

    return bResult;
  }

private:
    // The map container. The default sorting criterion used is less.
  std::map < keyT, objT >                   m_ObjectsMap;   
  
  // The iterator used to iterate the map
  std::map <keyT, objT >::const_iterator    m_Iterator;

    // Mutex used for syncrhonizing the map
  CHmpMutex                             m_Mutex;    
};
#endif // _C_SYNCHRONIZED_MAP_H


Als we een file compileren die deze header-file meeneemt, worden we verrast met de volgende compiler warnings / errors (ik heb de regelnummers ook even kloppend gemaakt met bovenstaande code snippet):
code:
1
2
3
Warning 1   warning C4346: 'std::map<keyT,objT>::const_iterator' : dependent name is not a type z:\synchronizedmap.h    128
Error   2   error C2146: syntax error : missing ';' before identifier 'm_Iterator'  z:\synchronizedmap.h    128
Error   3   error C4430: missing type specifier - int assumed. Note: C++ does not support default-int   z:\synchronizedmap.h    128


Het gaat uiteindelijk om het eerste stukje: template <typename keyT, typename objT> en de private data members van deze class.

Alvast bedankt en ik hou jullie ook op de hoogte...

Verwijderd

De compiler zeurt omdat hij const_iterator niet kan afleiden van de template types, in jouw geval keyT en objT.

Probeer het eens met 'typename'.

Verwijderd

Topicstarter
Verwijderd schreef op woensdag 14 mei 2008 @ 16:24:
De compiler zeurt omdat hij const_iterator niet kan afleiden van de template types, in jouw geval keyT en objT.

Probeer het eens met 'typename'.
Bedankt voor je reactie, maar hoe doe ik dit dan? Want het volgende verbeterd niets aan de compiler output:
code:
1
std::map <typename keyT, typename objT >::const_iterator    m_Iterator;


Ik meende dat de regel template <typename keyT, typename objT>, welke vooraf gaat aan de class (bovin in de file), hier al voor zorgt. Of praten we nu over iets anders?

Thanks

[ Voor 12% gewijzigd door Verwijderd op 15-05-2008 14:59 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ja, jullie praten over iets anders. Een std::map<A,B>::const_iterator kan een type zijn, maar ook constante of een functie of een variabele. Op het moment dat jouw template geparsed wordt zijn de 'waarden' van A en B nog niet bekend, en dus kan er ook niet opgezocht worden wat std::map<A,B>::const_iterator is. In dat geval wordt er gewoon uitgegaan van het feit dat const_iterator geen type is, en als dat wel zo is dan moet je er typename voorzetten:
C++:
1
typename std::map<A,B>::const_iterator bla;


De error zegt dat const_iterator een dependent type is. Hij is namelijk afhankelijk van de waarden A en B in jouw template

[ Voor 10% gewijzigd door .oisyn op 15-05-2008 15:16 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Punkie
  • Registratie: Oktober 2005
  • Laatst online: 07-11 20:36
In de std::map kan een type gedefinieert zijn met de naam const_iterator,
C++:
1
typedef int* const_iterator;

maar ook een datamember
C++:
1
static int* const_iterator


Welke van de 2 het is, weet de compiler nog niet bij het invullen van de templates (je weet wel, C++ => preprocessing). Vandaar het gebruik van typename, om de compiler te vertellen dat dit een type is (omdat hij default aanneemt dat dit een een variabele is.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Wat ik dus net al zei ja :P. Preprocessing heeft er trouwens weinig mee te maken.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Punkie
  • Registratie: Oktober 2005
  • Laatst online: 07-11 20:36
hmm, idd een foutje, templates worden niet geparsed tijdens preprocessing. Tijdens compilatie wordt, bij het aantreffen van een instantie van een template, de template parameters ingevuld en het resultaat gecompileert. Het invullen van de parameters is echter geen c++ preprocessing.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 08:45

.oisyn

Moderator Devschuur®

Demotivational Speaker

Het gaat in twee fases. De eerste is bij de definitie van de template, de tweede bij de instantie van de template. Die eerste fase is tevens ook de reden waarom je de compiler moet instrumenteren wat een type is en wat niet, omdat ie de code anders niet goed kan interpreteren. Overload resolution gebeurt voor het grootste deel ook al tijdens de eerste fase - in de tweede fase komen slechts associated namespaces van dependent names erbij.

VC++ slaat de eerste fase helemaal over en doet alles in de tweede fase, en daarom had VC++ 6.0 de typename dan ook niet nodig. In VC++ 2003 (geloof ik) zijn de regels aangescherpt en werd het gebruik van 'typename' verplicht daar waar dat volgens ISO C++ nodig was, om meer conform te zijn met de standaard - maar dus niet omdat de compiler het nodig heeft.

Maar two fase name lookup doet het nog altijd niet, en daarom gaat dit fout:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

void foo(double)
{
    std::cout << "foo(double)" << std::endl;
}

template<class T> void bar(T t)
{
    foo(t);
}

void foo(char)
{
    std::cout << "foo(char)" << std::endl;
}

int main()
{
    bar('3');
}


Dit zou "foo(double)" moeten outputten. VC++ output "foo(char)", omdat hij de name lookup pas tijdens template instantiation (in main() dus) toepast. Maar foo(char) hoort niet bij de lijst van mogelijke overloads, omdat die tijdens template definition time nog niet bekend was en de global namespace geen associated namespace van char is (waardoor foo(char) in de tweede fase tijdens template instantiation er dus ook niet bij komt).

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Verwijderd

Topicstarter
Aan allen:
Bedankt voor de uitgebreide info en vooral ook de extra achtergrond info.

Nu kunnen we tenminste verder!
Pagina: 1