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 money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
newsomnuke
Feb 25, 2007

Avenging Dentist posted:

Yes of course. Because it's not passing the same pointer around.
I know that. I realise my problem is more fundamental: a function can take a pointer to a class Base, and that pointer can in reality point to a derived class Der. However, the function copes with this because Base's members are at the same offsets as they are in Der right? That's my understanding as to how classes are laid out in memory. But if Der is in fact derived from both Base and some other class, its Base members may be at different offsets, so how does the function know this?

Adbot
ADBOT LOVES YOU

Vanadium
Jan 8, 2005

At the point where the Der pointer was converted to a Base pointer, it was changed to point to the Base subobject. That is why dynamic_cast had to be magic to get the original pointer back.

newsomnuke
Feb 25, 2007

Ah, I get it. Thanks.

That Turkey Story
Mar 30, 2003

Mustach posted:

This is why static_cast works for them. dynamic_cast is necessary for downcasts (base to derived) and sidecasts (e.g. across an inheritance diamond).

static_cast is fine for downcasts given that you know that your object is an instance of what you are casting to (or derived from that type) and is often preferable. You also can't use dynamic_cast unless the type you are casting from is polymorphic (it needs at least one virtual function). You should generally default to using static_cast for both up and down casts when you can and use dynamic_cast only when you have to. Times you have to use dynamic_cast are sideways casts or when a child inherits virtually or if you don't know if the cast can succeed.

Avenging Dentist
Oct 1, 2005

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

That Turkey Story posted:

:words:

You should get on AIM/IRC. I have ideas for a C++ killer.

That Turkey Story
Mar 30, 2003

I don't use AIM anymore. AIM is lame.

That Turkey Story
Mar 30, 2003

Also, if you wanna be cool, you can use my new fangled C++0x multi_cast!

http://www.codepaste.net/iqzbiz

code:
#include <utility>
 
template< typename SourceType >
SourceType&& multi_cast( SourceType&& source )
{
  return source;
}
 
template< typename     TargetType
        , typename ... IntermediateTypes
        , typename     SourceType
        >
TargetType multi_cast( SourceType&& source )
{
  return static_cast< TargetType >
         ( multi_cast< IntermediateTypes... >
           ( std::forward< SourceType >( source ) )
         );
}
 
////////////////////
// Example usage: //
////////////////////
struct left {};
struct right {};
struct child : left, right {};
 
int main()
{
  child child_;
  left& left_ = child_;
  right& right_ = multi_cast< right&, child& >( left_ );
}

raminasi
Jan 25, 2005

a last drink with no ice
Ok so I'm chewing my way through Elements of Programming, I'm glad I bought it, and I feel like I understand much better what generic programming is about.

What the book doesn't explain is why C++ is the language of choice for this. Now I'm not tremendously experienced with either C++ or any of its competitors, so I'm not looking to start an argument, just a "here is something C++ can do which no other language can do" (or maybe "here is something C++ can do which no other language with comparable development tools and libraries can do"). Is the multi-cast just posted an example? Is the STL an important part of the answer?

Avenging Dentist
Oct 1, 2005

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

GrumpyDoctor posted:

What the book doesn't explain is why C++ is the language of choice for this.

No other language has the necessary features to do generic programming in a sensible manner. Among the features required are templates (generics don't quite get all the way, but that of course depends on the implementation) and the decoupling of value/reference semantics from types (i.e. there are no "reference types" in C++, at least not in the sense that Java/C# have them).

GrumpyDoctor posted:

Is the STL an important part of the answer?

No, but the STL is an example of what you can do with generic programming (though it's full of bad stuff too, in an effort to appease the standards body).

That Turkey Story
Mar 30, 2003

GrumpyDoctor posted:

Ok so I'm chewing my way through Elements of Programming, I'm glad I bought it, and I feel like I understand much better what generic programming is about.

What the book doesn't explain is why C++ is the language of choice for this. Now I'm not tremendously experienced with either C++ or any of its competitors, so I'm not looking to start an argument, just a "here is something C++ can do which no other language can do" (or maybe "here is something C++ can do which no other language with comparable development tools and libraries can do"). Is the multi-cast just posted an example? Is the STL an important part of the answer?

If you are looking for a practical code example apart from just theory, yes, STL is a good example, and even more-so, the Boost Graph Library. There are other languages suitable for generic programming, I.E. Haskell is often the one mentioned, though C++ still does have some advantages there too and vice-versa.

If I had to narrow it down to a few important reasons that C++ is so much better suited for generic programming than languages like C# and Java, it's in its ability to represent associated types, to use types in functions at compile-time (in C++ via template metafunctions), to overload functions and to use type information to pick overloads/specializations of functions and types at compile-time. Along with this, you need the ability to separate generic algorithms from types and their intrinsic operations. Without these fundamentals you cannot create libraries like the STL or the Boost Graph Library or fully express pretty much any generic library (in the Stepanov sense of Generic Programming).

You can't, for instance, write a generic algorithm in Java that operates on any forward range and automatically dispatches to specialized versions based on further concept information (I.E., what further concepts are modeled by the range). As an example, in C++ there is binary_search which has (at minimum) two different implementations -- one for forward ranges and another for random access ranges. Which algorithm is used is picked up automatically based on what category of iterators you pass in.

This binary search is completely separate from operands it works on, in other words there is not a handwritten implementation for arrays or vectors or lists or deques. Further, none of those types or their associated iterator types have to inherit from a common base in order to be usable with the algorithm. If you choose to make your own container type, or if you have an already-made container from another library, you can use the algorithm without having to make a special definition for your type. In fact, you don't even have to modify your type! You can be using some pre-compiled C library that you can't change which has no knowledge of std::binary_search and yet still be able to use its containers with binary_search. All thats needed is a one-time specification of glue code (done usually with type traits and argument dependent lookup). No changes have to be made to the container itself, unless of course it simply isn't capable of the equivalent of basic iterator operations.

Still, taking it a step beyond that, if you really wanted to, you could write a special definition for the algorithm with respect to your types if you can make one even more optimized (or at an even higher level, with respect to further concept refinements as is done often with segmented iterators, allowing a generic specialization). Any special version you write is automatically picked based on type data. Users of your types and of the algorithms need to know nothing about these implementation details, all they do is call binary_search and pass in their data. The compiler figures out exactly the dispatching and at absolutely no runtime cost. You can just as easily call binary_search with std::list iterators as you do std::vector iterators yet you get two very different implementations underneath, and remarkably, neither of those underlying algorithms were written directly for std::list or std::vector, they are entirely generic and are picked based on what concepts the operands to the algorithm model. There is no directly link between algorithms and types, they are done through the level of abstraction known as "concepts".

The above is all extremely important. It means that any code you write, particularly if you are writing even higher-level generic algorithms that work with other generic algorithms internally, automatically takes advantage of these specializations implicitly. No matter how high of a level of abstraction you get, your algorithms are dispatched accordingly in the most specialized way possible at every single level. For instance if A calls B which calls C which calls D and E, when calling A, specialized versions of B, C, D, and E are all picked automatically. This is all done without the user ever having to know anything about implementation details and yet they still get as efficient code as if they had handwritten the algorithm for their type (unless of course there is a special implementation for that type or a concept it models, in which case they can write a special version which is again picked up automatically by anyone using that code).

As was mentioned, STL is a good example of this, but the Boost Graph Library even more-so. With it you can take any graph implementation whether it is a datastructure you wrote, an ad-hoc implementation in your code, a graph from some premade library, or one of the graph implementations provided by the Boost Graph Library itself, and be able to use any of them with the BGL's algorithms. All it takes is minimum, 1-time glue code that you can write in a way that is non-intrusive to both your graph code and to BGL code.

raminasi
Jan 25, 2005

a last drink with no ice

Avenging Dentist posted:

No other language has the necessary features to do generic programming in a sensible manner.

That Turkey Story posted:

There are other languages suitable for generic programming, I.E. Haskell is often the one mentioned, though C++ still does have some advantages there too and vice-versa.

Both of you were very helpful, but these parts seem to contradict each other...?

ShoulderDaemon
Oct 9, 2003
support goon fund
Taco Defender

GrumpyDoctor posted:

Both of you were very helpful, but these parts seem to contradict each other...?

Haskell can do the generic part just fine, but if you want to actually produce something the "programming" aspect becomes tricky. Fortunately, you can just embed a real language in a monad and get actual work done that way.

Edit: More seriously, C++ is far and away the best mainstream language for generic programming. There are more than a few "fringe" languages like Haskell which can do many of the same things. For example, in Haskell you mostly accomplish generic programming through typeclassing, which is a very small and simple-to-understand type system extension with very predictable effects, whereas in C++ the template system is very much evolved to solve many different problems as well as generic programming, and as a result is harder to completely understand and debug. That said, Haskell is very much a toy language compared to C++; Haskell's module system is clearly not suited for large projects, it is difficult-to-impossible to add functionality to existing typeclasses, there's only the most primitive form of scope protection, etc.

ShoulderDaemon fucked around with this message at 21:22 on Jan 28, 2010

That Turkey Story
Mar 30, 2003

GrumpyDoctor posted:

Both of you were very helpful, but these parts seem to contradict each other...?

Any contradiction should have been cleared up by the rest of our posts. "Sensible manner" is a subjective phrase and I think I was pretty clear in the objective qualities that make Generic Programming feasible in C++. Out of most statically-typed mainstream languages (particularly C#, C++, Java, C), C++ is the only one you can do Generic Programming in in the sense that Stepanov describes it, unless you consider Haskell mainstream, though again, neither of these languages is really ideal. Of all the features I describe as being fundamental to Generic Programming, look at the subset of languages that support them all and you will get the languages that let you do Generic Programming to the extent that C++ can (most languages fall way behind).

If that isn't clear, read this (old but still relevant) which has a much more detailed table of features that aid in Generic Programming and has direct comparisons between some languages along with an attempt to implement a generic graph library in those languages. This paper is good as well.

Avenging Dentist
Oct 1, 2005

oh my god is that a circular saw that does not go in my mouth aaaaagh
More to the point, I don't know Haskell.

raminasi
Jan 25, 2005

a last drink with no ice
Thanks for those papers. Have any of you ever looked into D for generic programming? I would love an excuse to learn/use D.
comparison of D and C++ templates (C++0x included)
D template constraints

Avenging Dentist
Oct 1, 2005

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

GrumpyDoctor posted:

Thanks for those papers. Have any of you ever looked into D for generic programming? I would love an excuse to learn/use D.

That syntax looks really bad, honestly. Also their comparison is crazily inaccurate, since it seems to be more "can you type pretty much the same thing and have it work in C++ or D?" rather than "does this feature exist in C++ and D?" For instance, they mention compile-time execution of functions and then claim that C++ can't do it, but it can, by way of metafunctions. Additionally, the constraints look like a not-very-good version of the ill-fated C++0x concepts, which themselves had a lot of problems.

One of the fundamental issues here is that creating a good generic programming language means (in my opinion) divorcing yourself from the mistakes that C and C++ made. D sorta tries to do this with respect to C++ only, but they don't go far enough, and in some areas, they don't improve at all. For instance, the "static if" syntax is boneheaded, since the compiler should know when you're dealing with a value known at compile time and just do it automatically.

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
The only thing that D has that I wish C++ had is invariant.

raminasi
Jan 25, 2005

a last drink with no ice

Mustach posted:

The only thing that D has that I wish C++ had is invariant.

A module system? Explicit scope guards? Decidable grammar?

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.
Modules would be really cool, but I don't yearn for them too frequently. Scope guards are provided nicely by Boost, so I don't need a keyword. And if the grammar got nicer, it just wouldn't be C++.

That Turkey Story
Mar 30, 2003

GrumpyDoctor posted:

D template constraints

D's template constraints are not terrible, but in practice they are no better than using enable_if in C++ since they only serve as a way to rule out overloads. All they've done is translated a library feature of C++ into a language feature. While this makes the syntax look cleaner in some sense, it doesn't provide any additional functionality. If you want truly effective constraints, you need a system that picks overloads based on what concepts the arguments model and prefers more refined concepts over less. Right now the only way you can somewhat simulate that is with tag dispatch.

defmacro
Sep 27, 2005
cacio e ping pong
Not sure where else to put this, I suppose I could make a new thread but I'll try here first.

I want to have two "sets" of iptables rules for a Linux kernel. One that can be modified by the administrator of the machine (like it currently is) and one that can only be modified by the kernel. I figured it wouldn't be too much of a pain to simply include the client code for iptables (so I don't have to recode all the parsing work) into the kernel, and duplicate all the target internal netfilter data structures to only work with the kernel version of iptables.

I doubt there's an easy way to handle the conflicting includes (without knowing a lot about the structure of the kernel). Is anyone familiar enough with netfilter to provide an alternative approach? I considered writing everything from scratch, but was hoping to save time reusing code.

EDIT: I guess to clarify: I want a kernel-space interface to the iptables rules in the kernel. This interface should create rules that can ONLY be removed by the kernel-space interface.

defmacro fucked around with this message at 21:32 on Jan 29, 2010

beuges
Jul 4, 2005
fluffy bunny butterfly broomstick
Is there a way using macro trickery or something similar to convert an enum value into a string representing that value?

e.g. say I have an enum defined as
code:
enum Commands
{
	InvalidCommand				= 0,
	Login					= 1,
	Logout					= 2,
	GetContacts				= 3,
	UpdateContactInfo			= 5,
...
};
and I want to do something like

code:
Command command = getcommand();

switch (command)
{
  case Login:
    handlelogin();
    break;

  case Logout:
    handlelogout();
    break;

  default:
    printf("Not handling command %s", ENUMTOSTRING(command));
    break;
}
Can I create a ENUMTOSTRING macro that somehow takes whatever enum value 'command' evaluates to, and just adds quotes around it or something? I could of course write a const char* ENUMTOSTRING(enum) function, but that's work and requires the function to be kept in sync with changes to the enum :negative:

Vinterstum
Jul 30, 2003

beuges posted:

Is there a way using macro trickery or something similar to convert an enum value into a string representing that value?


Yep.

#define PRINT_MY_ENUM(myEnum) printf(#myEnum)

void printSomeEnums()
{
PRINT_MY_ENUM(SomeEnum);
}

Brecht
Nov 7, 2009

beuges posted:

Is there a way using macro trickery or something similar to convert an enum value into a string representing that value?
...
Can I create a ENUMTOSTRING macro that somehow takes whatever enum value 'command' evaluates to, and just adds quotes around it or something?
code:
 ...
 default:
     printf("Not handling command %d", static_cast<int>(command));

Mustach
Mar 2, 2003

In this long line, there's been some real strange genes. You've got 'em all, with some extras thrown in.

Vinterstum posted:

Yep.

#define PRINT_MY_ENUM(myEnum) printf(#myEnum)
Are you being snarky or do you just not know how macros work? Because that doesn't work for his given use case; it'll just print "command".

Mustach fucked around with this message at 15:08 on Jan 30, 2010

beuges
Jul 4, 2005
fluffy bunny butterfly broomstick

Brecht posted:

code:
 ...
 default:
     printf("Not handling command %d", static_cast<int>(command));

Sorry, to be more clear, I want it to print out "Commands::UpdateContactInfo" or just "UpdateContactInfo" instead of "5"

BigRedDot
Mar 6, 2008

I wrote something to do this as a pet project with Boost::preprocessor, but you had to use a macro and some wonky syntax to declare the enum as well. Despite making something that worked, I never really considered it actually worth using.

mr_jim
Oct 30, 2006

OUT OF THE DARK

beuges posted:

Is there a way using macro trickery or something similar to convert an enum value into a string representing that value?

e.g. say I have an enum defined as
code:
enum Commands
{
	InvalidCommand				= 0,
	Login					= 1,
	Logout					= 2,
	GetContacts				= 3,
	UpdateContactInfo			= 5,
...
};
and I want to do something like

code:
Command command = getcommand();

switch (command)
{
  case Login:
    handlelogin();
    break;

  case Logout:
    handlelogout();
    break;

  default:
    printf("Not handling command %s", ENUMTOSTRING(command));
    break;
}

Not a macro, but make an array of strings, in the same order:

code:
char const *CommandNames[] = {
    "InvalidCommand",
    "Login",
    "Logout",
    "GetContacts",
    "UpdateContactInfo"
}
Then just index into the array:

code:
printf("Not handling command %s", CommandNames[command]);
The downside being that you have to change the string array every time you change the enum. And you have to be sure that the index you get is actually in range for the enum. (C doesn't do range-checking for enums, not sure about C++).

StackOverflow has some other suggestions.

mr_jim fucked around with this message at 16:32 on Jan 30, 2010

Brecht
Nov 7, 2009

beuges posted:

Sorry, to be more clear, I want it to print out "Commands::UpdateContactInfo" or just "UpdateContactInfo" instead of "5"
Then an enum is not what you want. Is the user entering numbers? If so, it's true that you can entice a number to an enum, but it's not "correct" in that the user isn't entering an enum, they're entering a number. You should handle that case like this:

code:
std::map<int, std::string> number_command_map;
number_command_map[1] = "do something";
number_command_map[2] = "do something else";
...
std::map<int, std::string>::iterator target = number_command_map.find(user_entry);
if (target != number_command_map.end()) 
{
    printf("You typed %d, which means command %s\n", target->first, target->second);
}
else
{
    printf("%d isn't a valid choice\n", user_entry);
}

beuges
Jul 4, 2005
fluffy bunny butterfly broomstick
Aha... that's too much effort then - I just wanted something quick to use for debug logging, but creating a map or array (the array idea won't even work because not all the enum's I want to log about are sequential) is going to be too much of a bother. Guess I'll have to look up the numbers against the enum declarations as they come up.

ctz
Feb 6, 2003
Declare your enum using a construction like this, in some header:

code:
#define FOO_ENUM_MEMBERS \
  ENUM_DECL(Apple) \
  ENUM_DECL(Pear) \
  ENUM_DECL(Orange) \
  ENUM_DECL(Blackcurrent) \
  ENUM_DECL(Pumpkin)

enum Foo
{
#define ENUM_DECL(nn) nn,
FOO_ENUM_MEMBERS
#undef ENUM_DECL
  Foo_MAX
}

extern const char *Foo_to_string(enum Foo e);
(If you want the enum's members to have manually assigned values, you'll probably want to have ENUM_DECL take two arguments rather than one here).

Now the implementation of Foo_to_string is:

code:
const char *Foo_to_string(enum Foo e)
{
  switch (e)
  {
#define ENUM_DECL(nn) case nn: return #nn;
FOO_ENUM_DECLS
#undef ENUM_DECL
  default: return "Unknown Foo";
  }
}

Brecht
Nov 7, 2009

ctz posted:

Declare your enum using a construction like this, in some header:
D:

Fedaykin
Mar 24, 2004
Hey guys, I'm somewhat new to programming but I've been trying to make a program that creates fractals. I've been able to make fractals with the color of a point outside the fracal related to the number of iterations it take to exceed the radius. For example this code...

code:
void pic::fractal()
{	
	for(int i = 0;i < height-1;i++)
	{
		for(int k = 0;k < width-1;k++)
		{
			double x = 0;
			double y = 0;
			double x0 = k*(xMax-xMin)/width+xMin;
			double y0 = i*(yMax-yMin)/height+yMin;
			int iteration = 0;
			int max_iterations = 1000;
			
			while( x*x + y*y <= (2*2) && iteration < max_iterations)
			{
				double xtemp = x*x - y*y + x0;
				y = 2*x*y + y0;
				x = xtemp;
				iteration++;
			}
			int color[3] = {0,0,0};
			if (iteration < max_iterations)
			{
				color[0] = iteration%2*255;
				color[1] = iteration%2*255;
				color[2] = iteration%2*255;
			}
			addPoint(k,i,color);
		}
	}
}
^^^This code works and produces a picture similar to This. Now I want to create a fractal that looks like This.

I've looked at
http://www.codeproject.com/KB/cs/Mandelbrot_set.aspx
http://linas.org/art-gallery/escape/smooth.html
etc but I can't produce a smooth exterior color gradient.

So the question is how do I fill in the missing part of the code vvvvhere
code:
void pic::fractal()
{	
	for(int i = 0;i < height-1;i++)
	{
		for(int k = 0;k < width-1;k++)
		{
			double x = 0;
			double y = 0;
			double x0 = k*(xMax-xMin)/width+xMin;
			double y0 = i*(yMax-yMin)/height+yMin;
			int iteration = 0;
			int max_iterations = 1000;
			
			while( x*x + y*y <= (2*2) && iteration < max_iterations)
			{
				double xtemp = x*x - y*y + x0;
				y = 2*x*y + y0;
				x = xtemp;
				iteration++;
			}
			int color[3] = {0,0,0};
			if (iteration < max_iterations)
			{
				double mu = (iteration - log(log(sqrt(x*x+y*y))))/log(2);
				/***************************
				^^Is that correct?
				WHAT DO I PUT HERE??
				***************************/
			}
			addPoint(k,i,color);
		}
	}
}

Avenging Dentist
Oct 1, 2005

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

Brecht posted:

Then an enum is not what you want.

Quit being stupid. 1) People have already posted solutions that work (albeit a bit messily), 2) he's already said this is just for debugging, which is a totally legit reason to do something like this.

Avenging Dentist
Oct 1, 2005

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

Fedaykin posted:

So the question is how do I fill in the missing part of the code

What are you confused about? You get the fractional escape count (you did that) and then map it to a color.

Vinterstum
Jul 30, 2003

Mustach posted:

Are you being snarky or do you just not know how macros work? Because that doesn't work for his given use case; it'll just print "command".

I was responding to the "Is there a way using macro trickery or something similar to convert an enum value into a string representing that value" part (you know, the bit I quoted), since it seemed the OP's main issue was that he didn't know about the # trick.

Fedaykin
Mar 24, 2004

Avenging Dentist posted:

What are you confused about? You get the fractional escape count (you did that) and then map it to a color.

http://linas.org/art-gallery/escape/smooth.html I don't want the 'bands' created by using the iteration integer.

Avenging Dentist
Oct 1, 2005

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

Fedaykin posted:

http://linas.org/art-gallery/escape/smooth.html I don't want the 'bands' created by using the iteration integer.

That doesn't explain what you're confused about? Your escape count in the second sample isn't an integer.

Fedaykin
Mar 24, 2004

Avenging Dentist posted:

That doesn't explain what you're confused about? Your escape count in the second sample isn't an integer.

ok, then my question is how do you apply that number and turn it into rgb?

Adbot
ADBOT LOVES YOU

Avenging Dentist
Oct 1, 2005

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

Fedaykin posted:

ok, then my question is how do you apply that number and turn it into rgb?

From your link: http://www.codeproject.com/KB/cs/Mandelbrot_set.aspx#premain1 (not how I'd do it)

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply