switch to another stl implementation - msvs intellisense stands still [solved]

Started by
8 comments, last by deffer 17 years, 10 months ago
After a painful battle with P.J.Plaugher's STL (that comes with VS 7.1) last night, I came to a conclusion that it SuckZ(tm). I decided to give a try to STLport. So I downloaded it. Installed. Changed INCLUDE paths in environment variables (sidenote: this did absolutely nothing, so if anybody has any clue where else I should change this, just bring it on). I added proper include paths to my project properties. And it works. But whenever I write, for example: #include <vector> and click: RMB -> "Open Document <vector>" I'm being sent to standard include files (...\MSVC7.1\Vc7\include) instead of my new path (...\MSVC7.1\Vc7\include\stlport). I know that this is a minor glitch, but it's annoying and slows me down. Anybody knows how to fix this? [Edited by - deffer on June 13, 2006 2:28:56 PM]
Advertisement
I know it's a little off topic (really, I know nothing about Visual Studio), but my experience with the implementation of the standard library that came bundled with VS 7.1 was pretty good, far better than STLPort, which is one reason why STLPort was pretty much abandoned when 7.1 came out.

What was the nature of your painful battle, if I may ask?

Stephen M. Webb
Professional Free Software Developer

I think the reason that you're getting the standard STL files first is because VS.NET searches the include directories defined in Tools->Options first, then the additional include directories in project options. I had a problem with this recently but didn't find any solution, the only work around was to delete the include directories in Tools->Options and add them to the include directories in project options after the directories I wanted to come first, then set the /X compiler option to ignore the standard include directories. It's a pain, but I searched for a while but found nothing other than this.

Hope that helps
Quote:Original post by perfectly_dark
I think the reason that you're getting the standard STL files first is because VS.NET searches the include directories defined in Tools->Options first, then the additional include directories in project options. I had a problem with this recently but didn't find any solution, the only work around was to delete the include directories in Tools->Options and add them to the include directories in project options after the directories I wanted to come first, then set the /X compiler option to ignore the standard include directories. It's a pain, but I searched for a while but found nothing other than this.

Hope that helps


Yes, I just found this out myself, and it worked! It also fixed the intellisense glitches. cool...


Quote:Original post by Bregma
I know it's a little off topic (really, I know nothing about Visual Studio), but my experience with the implementation of the standard library that came bundled with VS 7.1 was pretty good, far better than STLPort, which is one reason why STLPort was pretty much abandoned when 7.1 came out.

What was the nature of your painful battle, if I may ask?


On the other hand, I know nothing about other implementations of STL (yet)[grin]. But every day I see people using STLport and they are still alive'n'kickin', so it must not be so bad.

About the battle.
I was writing a custom allocator for std::list and std::map. Both failed miserably. Reason? Let's look at some snippet from list implementation:
template<class _Ty, class _Alloc>class _List_nod{  struct _Node;  // using _Node as template parameter!!!11  typedef typename _Alloc::template rebind<_Node>::other::pointer _Genptr;  struct _Node  {     // ...  };  // ...  typename _Alloc::template rebind<_Node>::other _Alnod;};

At the point where allocator is first instatiated with _Node, _Node is not defined. So my_allocator<T> may operate on T*, T& and so on, but if it wants to somehow use T itself, we're DOOMED. (Of course, we can use it in my_allocator's methods, but not in declaration).
I simply wanted to write
enum { ELEMSIZE=sizeof(T) };
inside my_allocator definition and I was flooded with... you know what.

In my oppinion, it is an idiosyncracy to write the implementation that way.
If I'm wrong, let someone correct me, please.
Quote:Original post by deffer
In my oppinion, it is an idiosyncracy to write the implementation that way.
If I'm wrong, let someone correct me, please.


Note how _Node contains two _GenPtr members. The library needs to query the allocator for the proper _Node pointer type before it can actually define _Node itself. That code is perfectly sane. Of course, it means that the rebind template (and thus the allocator) may get instanciated with an incomplete type. So be it. I can't think of another way of doing it.

Quote:I simply wanted to write
enum { ELEMSIZE=sizeof(T) };
inside my_allocator definition and I was flooded with... you know what.


Use sizeof(typename my_allocator<T>::value_type) instead of my_allocator<T>::ELEMSIZE where needed.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote:Original post by deffer
I simply wanted to write
enum { ELEMSIZE=sizeof(T) };
inside my_allocator definition and I was flooded with... you know what.


IMO you shouldn't, enumerations aren't made for storing constants. I don't have a compiler right now to check it, but couldn't you just do this:
...template<class T2>struct rebind{    ...    const static size_t ELEM_SIZE;};...


And in source file:
template<class T>template<class T2>const size_t allocator_name<T>::rebind<T2>::ELEM_SIZE = sizeof(T2);
Quote:Original post by CTar
IMO you shouldn't, enumerations aren't made for storing constants.


It is a common trick used with compilers which do not support inline initialization of static const integral member variables. 100% legit.

Some older compilers don't support class foo { static const int bar = 42; };
For those, class foo { enum { bar = 42 }; }; is an accepted workaround.

His real problem is doing sizeof on an incomplete type.

Quote:And in source file:

template<class T>...


You can't put templates in source files - the compiler won't know it needs to instanciate them when it processes the translation unit. Static member variables of class template actually get defined in header files too, surprising as it may be. But static constant integral member variables don't need it. They are true compile-time constants, not variables that get marked const.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote:Original post by Fruny
Note how _Node contains two _GenPtr members. The library needs to query the allocator for the proper _Node pointer type before it can actually define _Node itself. That code is perfectly sane.


STLport does not have this problem.
Quote:From STLport's <_list.h>

struct _List_node_base {
_List_node_base* _M_next;
_List_node_base* _M_prev;
};

No blahblahblah<T>::blahblahblah::pointer, but simply T*.

I know that I'm not the first one to imply that THE common stl implementation is a bit overcomplicated. Is this complication for a real reason? I don't know C++ that much to answer that question... I believe it is justified in most cases, but not all.


Quote:Original post by Fruny
Of course, it means that the rebind template (and thus the allocator) may get instanciated with an incomplete type. So be it. I can't think of another way of doing it.


From the top of my head:
template< typename T >class my_allocator{public:  template< typename U >  struct traits  {    typedef U  value_type;    typedef U* pointer;    //...  };  //...};template<class _Ty, class _Alloc>class _List_nod{  struct _Node;//typedef typename _Alloc::template rebind<_Node>::other::pointer _Genptr;  typedef typename _Alloc::template traits<_Node>::pointer _Genptr;  struct _Node  {     // ...  };  typename _Alloc::template rebind<_Node>::other _Alnod;};



Quote:Original post by Fruny
Use sizeof(typename my_allocator<T>::value_type) instead of my_allocator<T>::ELEMSIZE where needed.


This doesn't work for the same reason as original.
EDIT: Sorry, I misunderstood you at first. I thought you meant
enum { ELEMSIZE=sizeof(typename my_allocator<T>::value_type)};, silly me.
The thing is, I needed ELEMSIZE to be a template parameter for a member of my_allocator class.
Quote:Original post by deffer
I know that I'm not the first one to imply that THE common stl implementation is a bit overcomplicated. Is this complication for a real reason?


Clause 20.1.15-4 of the C++ Standard indicates that (standard) container implementers are permitted to assume that X::pointer is a T*, but does not require it. The Dinkumware library gives you additional flexibility. In table 32, it is indicated that allocate() returns an X::pointer, which must be a random access iterator -- again, it doesn't say it needs to be a T*. It could be a smart pointer, a 64-bit pointer ... whatever. The allocator requirements very carefully avoid ever requiring a T* there. Contrast with X::reference which must be a T&.

I don't see a requirement that allocators be instantiable with an incomplete type, but note that all the members that require knowledge of the size are implemented as member functions and thus only require that T be defined at the point where they are used.

Quote:The thing is, I needed ELEMSIZE to be a template parameter for a member of my_allocator class.


Then you're going to have to try to delay instantiation. Can you give more details?

[Edited by - Fruny on June 13, 2006 4:03:46 PM]
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Quote:Original post by Fruny
[...]all the members that require knowledge of the size are implemented as member functions and thus only require that T be defined at the point where they are used.
Quote:The thing is, I needed ELEMSIZE to be a template parameter for a member of my_allocator class.


Then you're going to have to try to delay instantiation. Can you give more details?


It's no big deal, actually. I was using some caching and kept a pointer to a slab (see: linux kernel) instance in my allocator. Slab is templated with element's size in my (re)implementation (wheather it is good or bad, is another matter).

I do can use ELEMSIZE in member functions only, but it requires somewhat more typing in each such function, which becomes a little messy, with casting here and there.

Also, I already switched to STLport, so there's no need to work this around anymore.

This topic is closed to new replies.

Advertisement