[Solved] template compilable with MSVC and does not compile with MinGW
-
I am trying to compile my application using Qt with MinGW under Qt creator. The application and all its libraries compile without issues with msvc 2005. The application uses both stl and Qt while most of the containers are really in stl and Qt is for GUI and communication used.
With MinGW I got compile errors with an extended template based on a stl map:
@
template < class T >
class KaSlimContBase : public std :: map < std :: string, T >
{
public:
KaSlimContBase ( );KaSlimContBase ( const std :: set < T > & st ); const_iterator findName ( T & val ) const // << line 41 { for ( const_iterator it = begin(); it != end(); ++it ) { if ( it->second->getName() == val->getName() ) return it; } return end(); } void cap ( const KaSlimContBase <T> & lhs, const KaSlimContBase <T> & rhs ); void cap ( const std :: set < T > & lhs, const KaSlimContBase <T> & rhs ); void cap ( const KaSlimContBase <T> & lhs, const std :: set < T > & rhs ); void print ( std :: ostream & os ) const; void printInfo ( std :: ostream & os, int level, int ident = 4 ) const;
};
@The compiler is not happy when returning a const_iterator in the marked line above.
@
..\InterfaceLib/KaSlim/KaSlimContBase.h:41: error: ISO C++ forbids declaration of 'const_iterator' with no type
..\InterfaceLib/KaSlim/KaSlimContBase.h:41: error: expected ';' before 'findName'__
@I have searched the Internet but all feedback I have found has been on when the return value of a function not specified (e.g. void, int, or more complicated std::vector<std::vector<char *> > I have found).
For the case above I have tried:
- std :: map :: const_iterator
- std :: map < std :: string, T > :: const_iterator
or more desperately - std :: map < std :: string, T > :: const_iterator < std :: string, T >
- const_iterator < std :: string, T >
Does anyone have good suggestions?
-
If you want to use the the STL iterator then you want to have a look at "this":http://www.qtcentre.org/threads/40255-How-to-use-STL-in-Qt
HTH.
-
Well, the stl support is apparently available, since a very basic program using Qt and stl string does compile without adding stl stuff.
For the code I have I would have expected that the compiler would complain for stl includes or when the map is used first a couple of lines up.
-
This file: mingw\include\c++\4.4.7\bits\stl_map.h
I found the comment:
@// many of these are specified differently in ISO, but the following are
// "functionally equivalent"
...
typedef typename _Rep_type::const_iterator const_iterator;
...
@Probably the implementation is not the same as msvc uses (I am no expert with STL, though).
-
Yes, you are right.
It is a nested template issue and the very same typedef.
Here is a small test with the standard Qt project example a bit furnished with stl.
@
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <string>
#include <map>class MyClass : public std :: map <std :: string, std ::string>
{
public:
int sizeValue () const
{
return size();
}
const_iterator myBegin()
{
return begin();
}
};template <class T>
class TMyClass : public std :: map <std :: string, T>
{
public:
int sizeValue () const
{
return std::map<std::string, T>::size();
}
const_iterator myBegin()
{
return begin();
}
};int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
std :: string str;return a.exec();
}
@With line 27 the problem starts. Even so the template is not used yet. I have tried using some of the stuff from the stl include, but did not arrive at a solution.
I decided to find another way to solve it.
Odd that some even old ms stuff outperforms other compilers/libs. Most developers claim the other way around ;-)
-
Hi Koahnig,
the problem is that const_iterator is template based on the paramete T. The following code solves your problem:
@
// test123.cpp : Defines the entry point for the console application.
//#include <string>
#include <map>class MyClass : public std::map <std::string, std::string>
{
public:
int sizeValue () const
{
return size();
}
const_iterator myBegin()
{
return begin();
}
};template <class T>
class TMyClass : public std::map<std::string, T>
{
public:
typedef map<std::string, T> _MyType;int sizeValue () const { return std::map<std::string, T>::size(); } _MyType::const_iterator myBegin() { return begin(); }
};
int main(int argc, char *argv[])
{
std::string str;MyClass a; TMyClass<int> b; return 0;
}
@
-
Ok,
i looked a bit deeper, and found a solution for you:
@
#include <string>
#include <map>class MyClass : public std::map <std::string, std::string>
{
public:
int sizeValue () const
{
return size();
}
const_iterator myBegin()
{
return begin();
}
};template <class T>
class TMyClass : public std::map<std::string, T>
{
public:
typedef typename std::map<std::string, T> _MyType;
typedef typename _MyType::const_iterator const_iterator;int sizeValue () const { return _MyType::size(); } const_iterator myBegin() { return _MyType::begin(); }
};
int main(int /argc/, char* /argv/[])
{
std::string str;MyClass a; TMyClass<int> b; return 0;
}
@The key was looking at the MinGW std::map code ;-)
This code compiled with MSVS2008SP1 and with MinGW 4.4.0
-
@Gerolf:
This does the trick. Thanks a lot.@Wilk:
Initially I started out with a class extending a bit the functionality of std::map. That worked fine.
I realized that the same extension would be handy for other objects in that context as well. So I wrote the extended template inheriting from stl::map. Wasn't any issue for msvc at all. Worked straight away and did what I needed.
Just minGW was not happy about the template and required a bit of convincing ;-)
It is on my list for considering a redesign, but certainly not right now. There are other areas of more importance to focus on.You might be right with your comment, but I do not see a way how aggregation or typedef might prevent the nested templates. Can you elaborate a bit more?
-
Your approach may be the only way of achieving a polymorphism, i.e. if your class is used instead of std::map in some places. I mean if you realy use that IS_A relation between your class and std::map. But if you don't use this relation you may try code like this:
@
template <class T, class TT> class C {
public:
C ();TT operator[](const T &key) { TT res; return res; }
private:
std::map<T,TT> m_map;
};
@
Probably it's not the best or just better way, but I think its a little bit more flexible, because you may change realisation without changing any other code, while if you use inheritence you may want to use IS_A relation, so you may have some problems if you'd like to change basic realisation of your class (KaSlimContBase). (Sorry for this long sentence and mistakes, English is not my native language) -
The idea was IS_A relation and to avoid repeating the same statements all over again. And certainly the debugging when the errors are repeated.
The encapsulation of map in my class is certainly an option, but this would require quite some replication of map access methods. So the decision was driven by my laziness ;-)PS: Do not worry about long sentences. I hear it all the time that I should make shorter sentences in English. I am not a native English speaker either ;-)