Search Amazon.com:
Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us $3,400 per month for bandwidth bills alone, and since we don't believe in shoving popup ads to our registered users, we try to make the money back through forum registrations.
«415 »
  • Post
  • Reply
Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

To reduce the burden on the generic Programming Questions thread (and to increase the chance that people will actually answer questions), here is the C/C++ Programming Questions thread! I will assume you all know how these threads work: ask questions, or answer them. 'nuff said.

Feel free to submit useful links for the OP, I'll try to maintain them.

I want to start programming, is C (or C++) a good starting language?
C++ might be a little much to learn for someone just starting out, but even so, the language you start with doesn't matter. If you have a specific project in mind that requires C/C++, by all means use it, but don't feel that you need to start with a particular language in order to get the "most" out of learning. However, if you intend to learn both C and C++, it may be best to start with C, since C++ is designed to build on C, and most of the knowledge from C transfers to C++ (but not necessarily vice-versa).

gently caress! I'm on Windows and my program works fine for me, but no one else can run it!
Deployment on Windows is a bitch. With multiple versions of the C runtime library, debug DLLs, redistributables, and more, chances are you're not going to get it to work on your first try. The following links (thanks to Mustach) should at least point you in the right direction:

Visual C++ Deployment
How to redistribute the Visual C++ Libraries with your application



Useful Guides: (thanks in part to That Turkey Story)
The C++ Standards Committee
C++ FAQ Lite
SGI's STL documentation
Thinking in C++
The C++ Source
Overview of Generic Programming
Exception Safety

Libraries:
Boost
GLib

GUI Libraries: (thanks Professor Science!)
Windows API
GTK
Qt
wxWidgets

Good Books:
The C Programming Language by Kernighan and Ritchie
The C++ Programming Language by Bjarne Stroustrup
Accelerated C++ by Andrew Koenig and Barbara E. Moo
Other recommended C++ books

Avenging Dentist fucked around with this message at Dec 12, 2009 around 04:58

Adbot
ADBOT LOVES YOU

That Turkey Story
Mar 30, 2003



Some more links:
The C++ Standards Committee
The C++ Source
Overview of Generic Programming
Exception Safety

Professor Science
Mar 8, 2006
diplodocus + mortarboard = party

GUI Libraies
Windows API
GTK
Qt
wxWidgets

fret logic
Mar 8, 2005
roffle


Awesome, this'll be a good place to ask.

Which should I learn, or if both, which first?

I like the looks of C, plus I just put Linux on my laptop and have a linux programming ebook for some low level C programming. I've used C++ for a little bit before, working out of that gigantic red C++ book (can't remember the name), but I don't remember getting into any O-O stuff.

I'm currently learning Java in school, and I'd like to pick up another language along the way. I'm also a little confused. Is there a difference between C++ and Visual C++? Does the Visual part of it just mean the Microsoft IDE, or is it more to do with libraries and specifically GUI programming?

ehnus
Apr 15, 2003

Now you're thinking with portals!

fret logic posted:

Awesome, this'll be a good place to ask.

Which should I learn, or if both, which first?

I'd say C first because C++ changes very little from C but throws a ton of other things your way as well that can be very overwhelming initially.

fret logic posted:

I'm currently learning Java in school, and I'd like to pick up another language along the way. I'm also a little confused. Is there a difference between C++ and Visual C++? Does the Visual part of it just mean the Microsoft IDE, or is it more to do with libraries and specifically GUI programming?

It's pretty much Microsoft's C++ distribution which includes the compiler, IDE, and some associated libraries. It's a bit of a misnomer, you don't need to do anything 'visual' with it at all, I use it at work and most of my programming just spits output to the console

Professor Science
Mar 8, 2006
diplodocus + mortarboard = party

It's very easy to hang yourself in C, but it will all be because of accidents and the all of the problems you cause will have the same fundamental cause (a bad pointer).

It's very easy to hang yourself in C++, except it will be because you used some language feature (actually, it'll be more like "you used some huge set of language features") that you didn't fully understand and now you've dug an inescapable hole. I really never got into the whole template thing or anything like that--I see the point, but I've never really seen a huge benefit in what I've worked on. So, I code in C++, but I use it as C with a few things that make it a lot more convenient (some OO, operator overloading, references, the STL, etc.).

Vanadium
Jan 8, 2005



Professor Science posted:

GUI Libraies
GTK

Fixed that. It is a nice wrapper that looks pretty C++ish and comes with a more comfortable signal/slots API than plain Gtk.

mracer
Feb 23, 2004
The M racer

Ok, more of a Visual Studio question. Whats the best way to step thru code with many macros. you know #define functions.

for example:
code:
#define COPY_PMV(adst,asrc) {                      \
  Ipp32s nn;                                       \
  for(nn=0; nn<sizeof(adst)/sizeof(Ipp32s); nn++)  \
    ((Ipp32s*)adst)[nn] = ((Ipp32s*)asrc)[nn];     \
}
is there an option for the debugger to show that instead of COPY_PMV(pointer,pointer) ?

Remulak
Jun 8, 2001
The four most over-rated things in life are champagne, lobster, anal sex and picnics. Oh, and that stupid children's book 'The Little Prince,' ugh.

I'm trying to think about cross-platform Windows/Mac compatibility for a the backend of a new project I've been working on. It's not a horribly complex project, since it's just a common C++ backend to a client that will have its own native frontends, but drat it's hard to figure out a good cross-platform way of doing things I'd normally lean on an MS API for.

What's bugging me now is package handling - ideally I need to deal with a zip file with some pictures, binary resources, text, and metadata. My first thought was OpenXML, specifically Open Packaging Convention, which is MADE for this and has a nice API. My second thought was *oh gently caress*, this won't work on the Mac. While it's submitted for standardization it doesn't look like there's a Mac or specific cross-platform C++ approach.

Is there a good, standard way to deal with this kind of problem from non-platform-specific C++? Or hell, some OPC solution for the Mac if we have to break this up? It seems kind of stupid to roll my own implementation for this, I can't believe it hasn't been solved before...

cronio
Feb 15, 2002
Drifter

mracer posted:

Ok, more of a Visual Studio question. Whats the best way to step thru code with many macros. you know #define functions.

for example:
code:
#define COPY_PMV(adst,asrc) {                      \
  Ipp32s nn;                                       \
  for(nn=0; nn<sizeof(adst)/sizeof(Ipp32s); nn++)  \
    ((Ipp32s*)adst)[nn] = ((Ipp32s*)asrc)[nn];     \
}
is there an option for the debugger to show that instead of COPY_PMV(pointer,pointer) ?

No, I'm fairly sure that doesn't exist.

Using sizeof here may be your problem though, if adst is a pointer like you say, sizeof is going to return 4 (or 8 if you're on 64 bit).

That Turkey Story
Mar 30, 2003



mracer posted:

Ok, more of a Visual Studio question. Whats the best way to step thru code with many macros. you know #define functions.

for example:
code:
#define COPY_PMV(adst,asrc) {                      \
  Ipp32s nn;                                       \
  for(nn=0; nn<sizeof(adst)/sizeof(Ipp32s); nn++)  \
    ((Ipp32s*)adst)[nn] = ((Ipp32s*)asrc)[nn];     \
}
is there an option for the debugger to show that instead of COPY_PMV(pointer,pointer) ?

For things like what you just posted you shouldn't really be using macros, just use inline functions, unless you want the code strictly C89. I don't know offhand if there is some kind of trick in Visual Studio to let you step through macros, but one portable trick that will work in all IDEs is to instead implement your macro as a #include (though you usually only want to do this with very long macros, especially if there is further preprocessor iteration during invocation).

For instance:
code:
/*******************************/
/* COPY_PMV.h */

Ipp32s nn;
for(nn=0; nn<sizeof(PARAM_adst)/sizeof(Ipp32s); nn++)
  ((Ipp32s*)PARAM_adst)[nn] = ((Ipp32s*)PARAM_asrc)[nn];

#undef PARAM_asrc
#undef PARAM_adst

/*******************************/

/*******************************/
/* Some other file */

void function()
{
  /* bunch of stuff here */

  #define PARAM_adst /* whatever */
  #define PARAM_asrc /* whatever */

  #include "COPY_PMV.h"
}

/*******************************/
Now when you step through you will be taken to what used to be a macro definition (and is now just the body of an included file). Again, I wouldn't do this for that particular example, but for complex macros that can't be turned into functions this can be very handy. It's hacky but it works.

Remulak posted:

What's bugging me now is package handling - ideally I need to deal with a zip file with some pictures, binary resources, text, and metadata. My first thought was OpenXML, specifically Open Packaging Convention, which is MADE for this and has a nice API. My second thought was *oh gently caress*, this won't work on the Mac. While it's submitted for standardization it doesn't look like there's a Mac or specific cross-platform C++ approach.

Is there a good, standard way to deal with this kind of problem from non-platform-specific C++?
I'm pretty sure Avenging Dentist is working on a cross-platform library like that right now, but I don't know how far along it is.

Doc Block
Apr 15, 2003

Pros only.


Remulak posted:

I'm trying to think about cross-platform Windows/Mac compatibility for a the backend of a new project I've been working on. It's not a horribly complex project, since it's just a common C++ backend to a client that will have its own native frontends, but drat it's hard to figure out a good cross-platform way of doing things I'd normally lean on an MS API for.

What's bugging me now is package handling - ideally I need to deal with a zip file with some pictures, binary resources, text, and metadata. My first thought was OpenXML, specifically Open Packaging Convention, which is MADE for this and has a nice API. My second thought was *oh gently caress*, this won't work on the Mac. While it's submitted for standardization it doesn't look like there's a Mac or specific cross-platform C++ approach.

Is there a good, standard way to deal with this kind of problem from non-platform-specific C++? Or hell, some OPC solution for the Mac if we have to break this up? It seems kind of stupid to roll my own implementation for this, I can't believe it hasn't been solved before...

For accessing the contents of a zip file, you could try zziplib or PhysicsFS.

Doc Block fucked around with this message at Feb 17, 2008 around 05:54

Entheogen
Aug 30, 2004

by Fragmaster


how exactly do << and >> work?
I know they are bitwise rotation to the left or right, but I think they eat up a carry that is 1>>1 = 0 instead of - max integer.

Remulak
Jun 8, 2001
The four most over-rated things in life are champagne, lobster, anal sex and picnics. Oh, and that stupid children's book 'The Little Prince,' ugh.

Entheogen posted:

how exactly do << and >> work?
I know they are bitwise rotation to the left or right, but I think they eat up a carry that is 1>>1 = 0 instead of - max integer.
You're right. They're what's called a logical shift. If it carried the bit around it would be a rotate.

FastEddie
Oct 4, 2003



Remulak posted:

You're right. They're what's called a logical shift. If it carried the bit around it would be a rotate.
No, they're bitwise shifts, because they operate on bits, rather than the boolean interpretation of the collections of bits. I have no idea what a logical shift would be.

Presto
Nov 22, 2002


FastEddie posted:

No, they're bitwise shifts, because they operate on bits, rather than the boolean interpretation of the collections of bits. I have no idea what a logical shift would be.
A logical shift is just shifting the bits without regard for what they mean.

I think the way it works is, if the object is unsigned, >> does a logical shift and the sign bit is not preserved. If the object is signed, it does an arithmetic shift which keeps the sign bit.

floWenoL
Oct 23, 2002

STRAW MAN

FastEddie posted:

No, they're bitwise shifts, because they operate on bits, rather than the boolean interpretation of the collections of bits. I have no idea what a logical shift would be.

Just another name.

floWenoL
Oct 23, 2002

STRAW MAN

Presto posted:

If the object is signed, it does an arithmetic shift which keeps the sign bit.

No, if the integer is signed and negative, the behavior is implementation-defined.

more falafel please
Feb 26, 2005

forums poster

mracer posted:

Ok, more of a Visual Studio question. Whats the best way to step thru code with many macros. you know #define functions.

for example:
code:
#define COPY_PMV(adst,asrc) {                      \
  Ipp32s nn;                                       \
  for(nn=0; nn<sizeof(adst)/sizeof(Ipp32s); nn++)  \
    ((Ipp32s*)adst)[nn] = ((Ipp32s*)asrc)[nn];     \
}
is there an option for the debugger to show that instead of COPY_PMV(pointer,pointer) ?

This will work if adst is an array, but not if it's a pointer (and not if it's an array that's degraded to a pointer in the current scope).

First off, you should use memcpy() or std::copy (if C++), because they're generally optimized beyond what you're going to write.

But if you want to debug this, I would suggest putting printfs/couts/however you log in the macro itself.
code:
#define COPY_PMV(adst,asrc) {                      \
  Ipp32s nn;                                       \
  for(nn=0; nn<sizeof(adst)/sizeof(Ipp32s); nn++)  \
  { \
    printf("nn=%d &(adst[nn])=%p &(asrc[nn])=%p asrc[nn]=%d\n", nn, &(adst[nn]), &(asrc[nn]), asrc[nn]); \
    ((Ipp32s*)adst)[nn] = ((Ipp32s*)asrc)[nn];     \
  } \
}

Entheogen
Aug 30, 2004

by Fragmaster


when i do a left shift, does the left most bit get sent to some carry register? on x86 machines, what would be the name of it?
I guess same would go for the right shift and right most digit.

I know how this works in PIC Micro controller, but I have no idea of how i would go about using it in C or assembler for x86.

Alan Greenspan
Jun 17, 2001



Entheogen posted:

when i do a left shift, does the left most bit get sent to some carry register? on x86 machines, what would be the name of it?
I guess same would go for the right shift and right most digit.

Assuming the SHL/SAL instructions are used by the compiler (generally a safe bet; but still something I'd put into a unit test), the Carry Flag (CF) contains the last bit that was shifted out of the value.

more falafel please
Feb 26, 2005

forums poster

Entheogen posted:

when i do a left shift, does the left most bit get sent to some carry register? on x86 machines, what would be the name of it?
I guess same would go for the right shift and right most digit.

I know how this works in PIC Micro controller, but I have no idea of how i would go about using it in C or assembler for x86.

If this isn't really performance-critical (like you're trying to avoid a couple more instructions and a jump per shift), I would go for the sure-fire cross-platform approach and check if the highest (or lowest for right shift) bit is set, and if so, bitwise-or it on to the lowest(/highest) bit of the result of the shift.

mracer
Feb 23, 2004
The M racer

more falafel please posted:

This will work if adst is an array, but not if it's a pointer (and not if it's an array that's degraded to a pointer in the current scope).

First off, you should use memcpy() or std::copy (if C++), because they're generally optimized beyond what you're going to write.

But if you want to debug this, I would suggest putting printfs/couts/however you log in the macro itself.
code:
#define COPY_PMV(adst,asrc) {                      \
  Ipp32s nn;                                       \
  for(nn=0; nn<sizeof(adst)/sizeof(Ipp32s); nn++)  \
  { \
    printf("nn=%d &(adst[nn])=%p &(asrc[nn])=%p asrc[nn]=%d\n", nn, &(adst[nn]), &(asrc[nn]), asrc[nn]); \
    ((Ipp32s*)adst)[nn] = ((Ipp32s*)asrc)[nn];     \
  } \
}

I know that this macro doesn't look optimize. (the goal of video encoding is to confuse ) But Intel loves to put them throughout their code. I didn't write the code but if i did i would inline and such. This was just one of the basic ones so i used it as an example. I think i will though take the printf advice and use it. thank you.

Jo
Jan 24, 2005



I've heard performance takes a serious hit when it comes to using immediate mode (a la glBegin() and glEnd()) versus using display lists.

If I'm rendering geometry that moves, changes textures, and has dynamic lighting, can I still use display lists?

Lexical Unit
Sep 16, 2003



Let's say I want to write this code:
code:
	const int N = 6;
	int A1[N] = {1, 3, 5, 7, 9, 11};
	int A2[N] = {1, 2, 3, 4, 5, 6};
	my_container result;
	std::merge (A1, A1 + N, A2, A2 + N, 
        	std::inserter (result, result.begin ()));
And have it work for the class I've written called my_container. Is there some kind of checklist of items I need to implement to get this to work, or do I need to write another class, say my_container_insert_iterator, and implement it myself (note this is what I've already done but I'd like to know if I can do away with it)?

Also, in trying to get code like that shown above to compile I was meet with this error from gcc 4.0.0:
code:
stl_algo.h: In function `_OutputIterator std::merge(_InputIterator1
	_InputIterator1, _InputIterator2, _InputIterator2, _OutputIterator)
	[with _InputIterator1 = int*, _InputIterator2 = int*, 
	_OutputIterator = std::insert_iterator<my_container>]':
	
main.cpp:183:   instantiated from here

stl_algo.h:2998: error: no match for 'operator=' in 
	'__result. std::insert_iterator<_Container>::operator*
	[with _Container = my_container]() = * __first2'
	
stl_iterator.h:531: note: candidates are: std::insert_iterator<_Container>& 
	std::insert_iterator<_Container>::operator=(typename _Container::const_reference)
	[with _Container = my_container]

stl_iterator.h:491: note:                 std::insert_iterator<my_container>& 
	std::insert_iterator<my_container>::operator=(const std::insert_iterator<my_container>&)

That Turkey Story
Mar 30, 2003



Lexical Unit posted:

Also, in trying to get code like that shown above to compile I was meet with this error from gcc 4.0.0:
code:
stl_algo.h: In function `_OutputIterator std::merge(_InputIterator1
	_InputIterator1, _InputIterator2, _InputIterator2, _OutputIterator)
	[with _InputIterator1 = int*, _InputIterator2 = int*, 
	_OutputIterator = std::insert_iterator<my_container>]':
	
main.cpp:183:   instantiated from here

stl_algo.h:2998: error: no match for 'operator=' in 
	'__result. std::insert_iterator<_Container>::operator*
	[with _Container = my_container]() = * __first2'
	
stl_iterator.h:531: note: candidates are: std::insert_iterator<_Container>& 
	std::insert_iterator<_Container>::operator=(typename _Container::const_reference)
	[with _Container = my_container]

stl_iterator.h:491: note:                 std::insert_iterator<my_container>& 
	std::insert_iterator<my_container>::operator=(const std::insert_iterator<my_container>&)

From the error it looks like you probably either did not define my_container::const_reference or you defined it incorrectly [Edit: Actually, it sounds only like the latter, not the former, since otherwise you'd get an error during instantiation of insert_iterator, not during the call]. When you are implementing custom containers and iterators and want to use them with standard library algorithms, just always make them compliant and you'll avoid issues like this. It's not much more effort than just adding proper typedefs/traits.

That Turkey Story fucked around with this message at Feb 17, 2008 around 23:39

Lexical Unit
Sep 16, 2003



Hrm, that may be the case but then is this not correct?
code:
typedef my_container& reference;
typedef const my_container& const_reference;
This is my "learn more about c++ by making a totally STL compliant container class" project and I'm trying to do it all by the book.

I have my own my_container_insert_iterator that I can pass to merge() which does the trick just fine, but I'd like to nix it in favor of std::insert_iterator<my_container> for neatness's sake. I already have const_iterator and iterator defined for my class and they work fine with STL algorithms, it's just the standard insert iterator that's giving me guff.

CupcakeCamper
Jan 8, 2008
Who killed the Milkman?

Jo posted:

I've heard performance takes a serious hit when it comes to using immediate mode (a la glBegin() and glEnd()) versus using display lists.

If I'm rendering geometry that moves, changes textures, and has dynamic lighting, can I still use display lists?


Yes, you can still use display lists, just do those modification before you call it.

Just try it out with some code and see. I haven't done OpenGL in a couple of months, but checking to see if animation within the object would be good to figure out.

Doc Block
Apr 15, 2003

Pros only.


Jo posted:

I've heard performance takes a serious hit when it comes to using immediate mode (a la glBegin() and glEnd()) versus using display lists.

If I'm rendering geometry that moves, changes textures, and has dynamic lighting, can I still use display lists?

Yeah, display lists are faster.

The fastest way, however, would be vertex arrays or VBOs.

Jo
Jan 24, 2005



Thanks for the responses.

kewlpc posted:

Yeah, display lists are faster.
The fastest way, however, would be vertex arrays or VBOs.

I did not know this. I thought display lists were faster because they were 'compiled' and stored.

Lexical Unit
Sep 16, 2003



Another question (still haven't solved the first as of yet):
code:
#include <iostream>
using namespace std;

template<typename T>
struct foo {
	// ...
	template<typename S>
	void bar(S l);
};

template<typename T>
template<typename S>
void foo<T>::bar(S l) {
	cout << "not an int: " << l << endl;
}

template<typename T>
template<>
void foo<T>::bar(int l) {
	cout << "an int: " << l << endl;
}

int main() {
	foo<int> f;
	f.bar ("test");
	f.bar (5);
}
Error:
code:
18: error: invalid explicit specialization before '>' token
18: error: enclosing class templates are not explicitly specialized
How do I specialize method templates of class templates?

Milde
Jan 17, 2004



Lexical Unit posted:

How do I specialize method templates of class templates?

I might be wrong, but I don't think C++ allows partial specialization of member function templates. Maybe something like this would work for you instead?
code:
template<typename T>
struct foo {
    // ...
    template<typename S>
    void bar(S l);

    void bar(int l);
};

// ...

template<typename T>
void foo<T>::bar(int l) {
    cout << "an int: " << l << endl;
}
This post outlines this problem.

Milde fucked around with this message at Feb 18, 2008 around 04:02

That Turkey Story
Mar 30, 2003



Lexical Unit posted:

Hrm, that may be the case but then is this not correct?
code:
typedef my_container& reference;
typedef const my_container& const_reference;
No. reference and const_reference are references to the value_type, not references to the container type. You should really get used to reading the error messages -- they are wordy, but everything you need to know about what you did wrong is there.

Thug Bonnet
Sep 22, 2004

anime tits ftw



Jo posted:

Thanks for the responses.


I did not know this. I thought display lists were faster because they were 'compiled' and stored.

Static VBOs, display lists, and other glDrawArrays() calls will be similarly speedy but proper buffer objects let you do cool things like make dynamic buffers that can be temporarily bound to local memory and manipulated (this comes in multiple flavors depending on how often you want to manipulate them). You can also obviously make then static, too.

Another advantage is that when you request memory on the video device you can just grab enough for all your mesh information (vertices, normals, colors, etc) and stack them end-to-end in the buffer. When you set up your pointers for glDrawArrays() you can use the offset within the VBO and you're in business!

You can also use PBOs to store texture data, which is nice because then you can stream it back into a texture right before you draw. This can be cool because then you can use the same methods that you would use for a dynamic VBO to manipulate your texture (by hand, animated textures, etc).

Lexical Unit
Sep 16, 2003



That Turkey Story posted:

No. reference and const_reference are references to the value_type, not references to the container type.
Thanks, that certainly clears up that mess. Not sure how you deciphered the exact problem from that error though, here's what my thought process was, line by line:

1. Ok, there's an error when I try to call merge().

2. It's this merge() call that's the problem on line 183 of main.cpp

3. In the STL code there's some operator*() calling a operator=() that either isn't defined or is bad.

4. One operator=() takes typename my_container::const_reference.
4a. Check that I have typedef for const_reference, I do, ok.

5. The other operator=() is just the copy-assignment operator for std::insert_iterator<my_container>

6. Huh... I don't get it. I've got const_reference typedefed, so what's the problem?

It never occurred to me that my_container::const_reference was wrong, though I can see now how that would logically be something further to check. And this error:
code:
stl_algo.h:2998: error: no match for 'operator=' in 
	'__result. std::insert_iterator<_Container>::operator*
	[with _Container = my_container]() = * __first2'
was a bit confusing so I wasn't even sure my reasoning about what the problem was was entirely correct. What's up with the __result. and * __first2? I'm not sure how to read that.

And when you say "get used to reading the error messages" do you mean simply from continued experience, or is there a better way you can suggest?

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh

Milde posted:

This post outlines this problem.

Lack of partial template specialization for functions pisses me off so much. I needed it for a project, and ended up writing wrappers to do it (though I ultimately changed my design a little to avoid it). Maybe I should clean up my wrappers somewhat and submit them to Boost.

Presto
Nov 22, 2002


floWenoL posted:

No, if the integer is signed and negative, the behavior is implementation-defined.
Yep, you're right. I wasn't sure and went with my gut instinct.

That Turkey Story
Mar 30, 2003



Lexical Unit posted:

Thanks, that certainly clears up that mess. Not sure how you deciphered the exact problem from that error though, here's what my thought process was, line by line:

...

...

3. In the STL code there's some operator*() calling a operator=() that either isn't defined or is bad. Note: Reread this error message, it's not operator*() calling operator=()...

4. One operator=() takes typename my_container::const_reference.
4a. Check that I have typedef for const_reference, I do, ok.

5. The other operator=() is just the copy-assignment operator for std::insert_iterator<my_container>

...

It never occurred to me that my_container::const_reference was wrong, though I can see now how that would logically be something further to check. And this error:
code:
stl_algo.h:2998: error: [b]no match for 'operator=' ... [/b]
was a bit confusing so I wasn't even sure my reasoning about what the problem was was entirely correct. What's up with the __result. and * __first2? I'm not sure how to read that.

You read it almost fully and were just about there but then you stopped! You already narrowed it down to pretty much being that the only thing your code was providing at compile-time here which was even showing up in the message was const_reference (sometimes it's a little bit harder than this and what you did wrong won't be mentioned explicitly). The main thing that tells you that it definitely was const_reference being improperly defined was:

code:
stl_algo.h: In function `_OutputIterator std::merge(_InputIterator1
	_InputIterator1, _InputIterator2, _InputIterator2, _OutputIterator)
	[with _InputIterator1 = int*, _InputIterator2 = int*, 
	_OutputIterator = std::insert_iterator<my_container>]':
	
main.cpp:183:   instantiated from here

stl_algo.h:2998: error: no match for 'operator=' in 
	'__result. std::insert_iterator<_Container>::operator*
	[with _Container = my_container]() = * __first2'
	
stl_iterator.h:531: note: candidates are: std::insert_iterator<_Container>& 
	std::insert_iterator<_Container>::operator=(typename _Container::const_reference)
	[with _Container = my_container]

stl_iterator.h:491: note:                 std::insert_iterator<my_container>& 
	std::insert_iterator<my_container>::operator=(const std::insert_iterator<my_container>&)
You kind of went through some of this already but I'll go through exactly the thought process I try to go through.

From the top, you know it's an error directly in the merge algorithm. It's extremely unlikely that your library's standard merge algorithm is implemented incorrectly and you are using a good compiler, so it's probably not some weird compliance problem. Assume it's how you're using it. The compiler tells you what types you used for iterators, which were just int*, so you can safely rule out that being the problem since pointers are valid iterators right out of the box, at least concerning compile-time type requirements (and since this is a compile-time error, that's all that would matter here).

The only other option is it's something wrong with your last type, std::insert_iterator<my_container>. Again, since insert_iterator is standard, it's very unlikely it's a problem in insert_iterator itself, so you probably are using it with a type that doesn't properly meet its requirements.

So then you get to:

code:
error: no match for 'operator=' in 
	'__result. std::insert_iterator<_Container>::operator*
	[with _Container = my_container]() = * __first2'
Which says that it's dereferencing and instance of insert_iterator<my_container> and then uses assignment to set it to *__first2. So in other words, you could imagine a hypothetical line:

code:
void foo( std::insert_iterator< my_container > your_insert_iterator, some_type __first2 )
{
  *your_insert_iterator = *__first2; // This line is where the error would be
}
Without going any further, if you know insert_iterator, you know that operator* just returns *this, so the problem is that there is no match for a plain-old call to = of insert_iterator< my_container >. If you didn't already know all of insert_iterator's assignment operators it lists them in the same error. The only two are the copy-assignment, which clearly can't be the problem, especially not from the compile-time error you're getting, and the one taking my_container::const_reference. This should jump out at you. Looking again at the context of the error message it is now equivalent type-wise to:

code:
your_insert_iterator = *__first2
You said you didn't know what __first2 was. Depending on what IDE you're using, you can likely just double-click your error message and it will take you to that line in code where you can see the type, or go to the line manually since it's listed next to the error (the type is all you need to know here since it's a compile-time error), but without even doing that, look at the context, *__first2 looks suspiciously like an iterator, which makes sense since this is a merge algorithm and you passed in iterators to it. In fact, "first", "middle", "last", "result", and "comp" are very often the parameter names used with standard library algorithms (and you may even be reminded of that when you type in "merge(" since most IDEs will pop up the signatures of the algorithm at that point).

Even if you didn't realize that immediately, still without following the link to the line in code, it looks fairly clear that *__first2 is probably an iterator being dereferenced and you passed in int* objects for iterators, so the statement is very likely to be similar type-wise to:

code:
int value;
your_insert_iterator = value;
Since we already narrowed down the problem to being that no assignment operator had valid parameters for that and that the one likely to be the problem was the one with my_container::const_reference as the parameter, from the context you can now see that const_reference should most likely be a reference to a const int here. Looking at your definition, you realize that you defined const_reference as a reference to the container rather than a reference to the value_type, which if you didn't already realize was wrong, should look at whatever you are using as a resource to double-check what its implementation should be, and short of that, you can just compare it to other standard containers.

Apart from that, you should usually try to be conscious of rationale when writing code. Having a nested const_reference type be a reference to the type it is a member of probably isn't too useful so that should maybe set off some bells when you are writing it. If you don't understand the design rationale behind the code you are using, you should try to learn it both so that you may use the code the way it was intended and so that you can use similar rationale in your own designs, especially if it is an extension of what is already written.

Really though, when making your container standards compliant you should have a good book or the standard at hand to tell you the requirements to begin with which would have helped you avoid this problem form the start (although, as a side note, requirements will all be explicit in code with C++0x which will pretty much even remove the need for any resource at all when making your types meet proper requirements, since type requirements along with axioms are a part of the code itself... with the exception of complexity requirements...).

Lexical Unit posted:

And when you say "get used to reading the error messages" do you mean simply from continued experience, or is there a better way you can suggest?
Mostly just from being confident in what you know about the language and making sure you understand fully what each part of the error says. They are usually wordy but overall not too complex. The wordiness just comes from telling you template arguments and other information which you may or may not need so that you can see if you made a mistake with your types. They're more just intimidating than anything else but underneath they're very often not much more complex than a regular error.

Lexical Unit
Sep 16, 2003



That Turkey Story posted:

You read it almost fully and were just about there but then you stopped!
Thanks for that awesome reply; I just re-read that error message and my brain was totally like, "oooooooohhhh... now I get it."

Well, back to work! FYI, I'm working on a Modern-C++-y trie class that supports any type as keys (so long as the user provides policies for their key type, defaults of course work with std::string). I'm basically modeling it more or less after std::set(). I think boost's spirit library has already implemented something like this as an implementation detail, I think they use a ternary search tree though. Fun stuff.

Adbot
ADBOT LOVES YOU

Doc Block
Apr 15, 2003

Pros only.


NM, reposting in Mac dev thread.

Doc Block fucked around with this message at Feb 19, 2008 around 14:12

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply
«415 »