mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

As thines01 points out, but more precisely, what you really seem to be trying to do is to create a Domain Specific Embedded Language (or DSEL for short).

This can be done directly in C++, to a large extent. However, it is far from easy. Generally, it involves a heavy amount of template meta-programming, specifically, a technique called expression templates. The most amazing example of this is probably the Boost.Spirit library, and if you just take a quick glimpse at it you will probably figure out that its internal mechanics are far from being easy to grasp.

If all you want to do is to be able to insert some custom code written in some other language (that you may or may not have invented yourself) inside a C++ source file, then I would suggest that you simply create your own pre-processor (or pre-pre-processor). It is easy to create a program or script and run it on the source files before gcc. Then, all you need is to look for that token (i.e. like your MACROs name) and then you can do whatever you want with the custom code you find there. I'm guessing you will also have to parse that code somehow anyways to either turn it into valid C++ code or do something else. So, as L7Sqr said, you should look into parsing libraries like lex and yacc, or even Boost.Spirit (which is a library for creating parsers and code-generators).

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

There are many problems with your code, here are some in-code comments:

class ANew
{
    private:
        vector<CustomType> ArrayOfTypes;
        int rows;

    public:
        ANew() {}
        ~ANew() {}

        CustomType& operator ()(int I)
        {
            return ArrayOfTypes[I];
        }

        CustomType& operator [](int I)
        {
            return ArrayOfTypes[I];
        }

        // You should not return a copy of the underlying vector, return a reference instead (notice the ampersand):
        operator const vector<CustomType>& () const
        {
            return ArrayOfTypes;
        }

        bool operator == (const ANew &AN) const // notice that this function should be const and should return a "bool" value.
        {
            return (ArrayOfTypes == AN.ArrayOfTypes);
        }

        bool operator != (const ANew &AN) const // ditto.
        {
            return !(ArrayOfTypes == AN.ArrayOfTypes);
        }

        // Don't use the = operator for doing an addition of an element to the array!
        //  Don't abuse operator overloading by redefining the semantics of the operator.
        //  The = operator means "assigning" not "inserting" or "adding an element".
        //  If you absolutely want an operator, use the << operator to add elements. 
        ANew& operator = (const CustomType& CT)         //Add the CustomType to ArrayOfTypes. Ex: ArrayOfTypes AN = CustomType X
        {
            //#define LEN(a) (sizeof(a)/sizeof(*a))
            // The LEN() macro doesn't make any sense.
            //  sizeof(this) will just be the size of a pointer on your computer. 
            //  sizeof(*this) is a fixed number (has nothing to do with the number of elements in the vector)
            // dividing those two gives a fixed and undefined value. 
            if (this[LEN(this)] != &CT)	 // here, you compare a pointer with an object!
            {
                this.push_back(CT); …
triumphost commented: TY =] Triumphost. +6
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

C is generally considered as a low-level to mid-level, functional programming language which moderately enforces an explicit and static type system. It provides native syntactic support for structured and procedural programming paradigms.

C++ is generally considered as a general-purpose (low- to high-level), multi-paradigm programming language which strongly enforces an explicit and static type system. It provides native syntactic support for many programming paradigms: structured, procedural, object-oriented, generic and pure-functional meta-programming.

The relation between C and C++ is simply a matter that the basic syntax is essentially the same, and that, a few compatibility issues aside, the C language is a sub-set of C++ (i.e. C code can generally be compiled with a C++ compiler, although there are some incompatibilities that are generally minor issues that are easily resolved).

Object-oriented programming is a programming paradigm (i.e. a way to think of and create a software design). The basic idea is to associate data and functions into one coherent entity (a "class", which, once instantiated, creates an "object"). But usually, when people talk of object-oriented programming (OOP), they also include, at least, the use of three fundamental features: encapsulation, abstraction and polymorphism. C++ is not a pure object-oriented programming language, because (a) OOP is only one of the programming paradigms C++ provides features for, and (b) real …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Start small and move on.

For example, you can start by writing a text-based RPG. Then, learn to use simple GUI systems like SDL to create 2D games, a good start could be a Nibbles game or Tetris. Finally, you can start to look at creating 3D games, I suggest you get acquainted with off-the-shelf libraries like Ogre3D which is going to do all the graphics rendering for you.

Once you have a few simple game running (to some extent) you can start to figure out what areas of game development you prefer to focus on (e.g. graphics rendering effects, software engineering, AI, animations, physics simulation, etc.).

And you're just about the right age and competence to start doing this. I know some people who started at your age with this passion and got hired right out of high-school in the computer game industry (I would have been one of them if I didn't choose to pursue engineering instead).

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Line 15 is an implicit conversion operator. The return type is const ANew* , and so, you need to return that. As in:

operator const ANew* () const
        {
            return this;
        }

But I have to say that I don't approve of this implicit conversion from value to pointer, it is dangerous.

As for the call-operator, you need to the correct return-type:

CustomType& operator ()(int I)
        {
            return ArrayOfTypes[I];
        }
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

If you use the Boost.Random library, there are plenty of different random number generators with all sorts of cycle lengths (including 2300000 bits).

The new C++ standard (C++11) also includes a random library with a lot of the generators from the Boost.Random library, but you need a fairly recent compiler to have that available. You can also use the underlying random number engines to create custom generators, the methods available are linear-congruential, mersenne-twister, subtract-with-carry, discard-block, independent-bits, and shuffle-order engines. There are plenty of options.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Here's my take on this. I mostly agree with most posters so far. Just adding my grain of salt.

Myth #1: " const variables are less efficient than #define s"
First, all const-variables are not the same. In this case, we are talking only about const-variables which could be (easily) replaced by a #define, so that limits things to POD-types (in the formal sense), meaning you won't have pesky little hidden mutables. Also, we have to make a distinction between static scope and an extern scope. A const-variable with static scope (which is the default, btw) will, by definition, always carry the value that it is given at the declaration-site. That's not true for extern const-variables because their values (or references to it) are resolved by the linker. So, in the case of a static const-variable, there is no reason why the compiler cannot replace the occurrences of the const-variable with its literal value, because that is well within the purview of the "as if" rule for code optimizations by the compiler, and, in fact, unless there are debugger-symbol requirements involved, most decent compilers will perform this optimization.

Second point is, as some have said already, the actual performance difference (if any) will be negligible compared to the macro-scoping issues like the logic of the algorithms, locality of reference, etc..


So, now that we know that efficiency-wise there won't be a noticeable difference between your 3 options, or at least, not enough to care …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The difference is purely semantics (and type-related), but that doesn't make the distinction a trivial one. Just like in English, we mean different things when we say "nothing", "no-one", or "nowhere", which correspond, analogously, in C++ to 0 , '\0' , and NULL (which was actually replaced by nullptr now). Just like in English, you won't say "this argument goes 'nothing'." or "I went to the mall, but at the end, I bought 'no-one'.", or "there was 'nowhere' left at the meeting when I arrived.". In C++, it's the same thing, each of these expressions are valid and meaningful in different contexts. The fact that they might have (and usually, do have) the same value to the computer (who doesn't care about semantics or context) is mostly irrelevant (unless you're actually doing the kind of low-level bit-tweaking code that requires you to know that). Just like the fact that "nothing", "no-one" and "nowhere", or any other expression to mark the absence of something, could all be mathematically interpreted as zero (or nil, or null, depending on your particular English dialect), but that doesn't make them all the same or equivalent, because, to us, humans, semantics and contexts are things that matter a lot!

Arguably, that's the most important thing that programming languages do, i.e., provide semantics and contexts, and tools (and rules) to organize them and obey them. We need that to be able to construct good software designs. So, don't say, because different things mean the same to …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The only thing that I can see that is wrong is the "Main.cpp" on line 6 of the last piece of code you posted.

If it still doesn't compile, please provide the error that it prints out.

Also, your multiplication operator is mathematically wrong, read up on complex numbers.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You create your Complex numbers without giving them an initial value (i.e. your default constructor gives no default value to the real and imaginary parts). Generally, you should do the following for your constructors:

class Complex
{
public:
	//Complex(); //don't provide a default constructor, instead, provide default values for the parametrized constructor:
	Complex(double r = 0.0, double i = 0.0);
	Complex operator+(Complex);
	Complex operator-(Complex);
	Complex operator*(Complex);
	bool operator==(Complex);
	bool operator!=(Complex);
	friend ostream &operator<<(ostream &, Complex &);
	friend istream &operator>>(istream &, Complex &);
private:
	double real;
	double imaginary;
};

With the above (and eliminating the definition of the default constructor), you should have default constructed Complex objects that have both real and imaginary parts being 0. After that, you should provide values to your complex numbers (either hard-coded values via parameters to the constructor, or input values from the user using the cin >> operator).

That should get rid of the "display really random numbers" problem, which was caused by having no initial values for your Complex numbers.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You need header-guards.

Simply do this for your header file:

#ifndef MY_COMPLEX_HEADER
#define MY_COMPLEX_HEADER

#include <iostream>
using namespace std;

class Complex
{
public:
	Complex();
	Complex(double, double);
	Complex operator+(Complex);
	Complex operator-(Complex);
	Complex operator*(Complex);
	bool operator==(Complex);
	bool operator!=(Complex);
	friend ostream &operator<<(ostream &, Complex &);
	friend istream &operator>>(istream &, Complex &);
private:
	double real;
	double imaginary;
};

#endif
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

If you call g++ with -std=c99 or any type of C standard specification, you must be compiling C code. It doesn't matter that the compiler is called "g++", if you tell it to compile C code, it will expect C code and only accept that.

The problem here is that if you added the extern "C" to your header file, but not to your .cpp file, then your code is neither in C++ nor in C, so neither a C compiler or a C++ compiler will accept it. The extern "C" is specific to C++ and tells to compiler to apply C linking rules (including no name-mangling) to functions contained in the curly-braces following it or the function directly following it. This specification has to appear in both the header file and the cpp file, and, it is not valid in C. So, either you put the extern "C" in both files and compile with a C++ compiler, or you don't use extern "C" anywhere and compile with a C compiler (or, equivalently, with g++ -std=c99 ). Also note that extern "C" only affects linking, so it doesn't tell the C++ compiler to compile that chunk of code as C code, it only instructs it to create a C-compatible external interface (for linking purposes) for that code. So, you need to code to be valid C++ code, which may not be the case since C++ is not entirely backward compatible with C, but generally it will be the case. …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Most examples that you posted were indeed bad style, wrong and/or inefficient. As for the weirdness of it, generally, straight-out weirdness usually originates from Frankenstein code, meaning that the code is often the result of piecing together inharmonious codes and/or the result of trial-and-error where a previous version used to require a particular thing (like using a shared_ptr instead of a unique_ptr or auto_ptr) which is no longer relevant or useful in the "final" version.

Now, of course, as WaltP said, some code might look alien to you, but that doesn't automatically mean that it is bad. There could be a justification that you don't know about. Certainly, AFAIK, this is not the case for the examples you posted. So, you should always question these things with an attitude that welcomes the "seniors" to teach you something new. However, that doesn't mean that you should accept empty arguments like:

> "there are historical reasons for doing this": historical reasons are not good reasons to justify a particular programming pattern, at best, it can serve to justify not changing something too much. Like if you had an old house that was partly damaged, you wouldn't destroy all that is left just because you could re-build it all with better materials and techniques, you would instead do a good job of fixing the damages with good and new materials and techniques and leave the rest as is. In other words, historical reasons don't serve to defend methods that are old, …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You need to show efforts of your own before you can hope to get help on specific problems you encounter while doing this assignment. We don't just do your homework for you, because that would not help you or anyone else.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Depending on the way that the DLL was compiled, it might be possible for you to use it from a VS2008 project.

The easiest solution, of course, is to contact the issuer of the library in question and ask for a VisualC++ import library (or the source code so that you can recompile the DLL yourself). If they don't want to bother providing that, then, besides cursing at them or considering finding another library with similar capabilities, you can read further.

First of all, the dll was compiled with MinGW (almost certainly). The .dll file contains the actual code and the .a file is called an "import library" (and the "a" stands for "archive" which is GNU jargon for "static library").

Second, all DLLs are not the same. The main thing that can be different is the name-mangling (which is a kind of encoding of the names of the functions) which is different from one compiler to the next (but usually, each compiler-vendor adopts some convention that make libraries compiled with different versions of the compiler compatible with each other). Generally, the name-mangling of one compiler(-brand) is not compatible with the name-mangling of another. Fortunately, the name-mangling can be disabled by specifying that the functions (and the library) should be compatible with or callable from C code, because C doesn't have or need name-mangling. So, if the functions in the headers (whose code are in the DLL) are all declared with extern "C" or within a giant …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

There are some limits to what you can do with a forward-declared type. In technical terms, a type that was forward-declared but not yet declared (the compiler has not reached the full declaration yet) is called an "incomplete type". The reason for that name is simple, the compiler doesn't have complete knowledge of what that type is, it only knows that it exists (or will exist in the future). So, you cannot write code that uses the class in any way, but, fortunately, you can use pointers or references to the class (but you cannot dereference them). In other words:

class MyClass; //forward-declaration

void f1( MyClass c ); // ERROR: incomplete type.

void f2( MyClass* p ); // OK!

void f3( MyClass& r ); // OK!

void f4( MyClass* p ) {
  p->someMember();   // ERROR: incomplete type.
};

Get it? The point is that the compiler can figure out what a pointer or reference looks like (in binary) without having complete knowledge of what it points to, all the compiler requires is that the pointer or reference points to an object of a valid class or type, and the purpose of the forward-declaration is to temporarily satisfy that requirement until the actual declaration appears.

So, when it comes to the code you posted, you can fix the compilation error by doing this:

struct Point
{
  //...
    Point MidPointBox (const Box& B);  // make it a reference.
  //...
};

struct Box
{
  //...
};

// then, put the …
triumphost commented: Thanks! +6
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

I assume you are referring to rvalue-references, not the logic "and" operator.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

That is obviously a return value optimization, I mean, it's a textbook example of NRVO. That's what you would expect any half-decent compiler to do.

I don't understand your question about the "limit" of NRVO. If you mean, how complex a situation can the compiler cope with, then I would guess that is pretty compiler-dependent.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Would Pentium 4 with 2gb good enough to run ubuntu?

I just installed Ubuntu 11.10 on a laptop with 2Gb and a core2 processor (which is pretty much the same generation as P4, it is a 4.5 year old laptop). It runs fine, a bit more slugish than Kubuntu 11.04 that I had installed on it before. I also had Vista installed on that laptop before and it was pretty slow (and idling at 65% of RAM). So, if you want a pretty flawless experience with Ubuntu on your system, you could go with an older version of Ubuntu or Kubuntu (I find that KDE (used for Kubuntu's GUI) is faster than Gnome (used for Ubuntu's GUI)), version 10.04 or 10.10 would be good candidates. One of the nice things with Linux distros is that generally, using an old version of the distros don't keep you from getting the latest software (the distro version mostly affects the look / features of the desktop environment (KDE or Gnome or else) and the hardware drivers (but if the hardware is old, it doesn't matter much)).

As for dual-booting, definitely, Windows has to be installed first. Then, you have to repartition under Windows (easier IMO) so that you get at least 20Gb of free-space (non-partitioned, unformated space) on the hard-drive, and you will never need more than 100Gb to have more than enough space for Ubuntu. The default install process of Ubuntu will install it on the free-space (if there is …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

If you run this with any kind of optimization (or even the base level), it will optimize the entire operations away, making it equivalent to number = 0xFFE0; .

You need to make the number change at run-time and you need to do the operation a lot of times too, maybe like so:

unsigned int and_operator(unsigned int number) {
  return number & (~0x1F);
};

unsigned int bit_shifting(unsigned int number) {
  return (number >> 5) << 5;
};

int main() {

  srand((unsigned int)time(NULL));
  
  for(unsigned int i = 0; i < 1000000; ++i)
    unsigned int result = and_operator( rand() );

  for(unsigned int i = 0; i < 1000000; ++i)
    unsigned int result = bit_shifting( rand() );
  
  return 0;
};

Then, you time the loops with whatever method you prefer.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You cannot separate the compilation of the function template from its declaration. Function templates are only compiled when they are used with a specific template argument, we call that instantiation. Your implementation of the function is never compiled in the cpp file because it is not used when you compile that cpp file, so the linker doesn't find it when you use it from another piece of code (translation unit).

The solution is that the implementation of that function template has to appear in the header file in which it is declared.

Read more about it here.

Allander commented: Quick and helpful reply. Many thanks! +0
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Of course, you can use malloc() but you have to be aware that it doesn't call the constructor, so, you have to do that yourself directly afterwards, through a placement-new operator.

The "initialize" function that you posted:

//create and initialize
void* initialize()
{
  MessageQueryTester* self = (MessageQueryTester*)malloc(sizeof(MessageQueryTester));
    memset(self, 0, sizeof(MessageQueryTester));
 
 return self;
}

is a repugnant piece of junk code.

You ask, is this safe? Hell no! You proved that yourself by causing it to crash when changing the container to a list instead of a vector. My guess is that setting all bytes to 0 of a vector object does not cause a crash, but that's just luck (probably, a vector only stores a pointer to the data and a size-value, and if you set both to zero it is an OK state for the object). And that is exactly how that code is expected to function: cause a later crash in most cases, go unnoticed on a few lucky(?) occasions.

There are two terrible errors in the code, (1) it uses memset to initialize the memory of the object which is completely wrong, and (2) it strips the type information out of the pointer it returns (and does a cast on that occasion, which has undefined behavior).

There are two correct options:
1) Use malloc and placement-new:

//create and initialize
MessageQueryTester* initialize()
{
  MessageQueryTester* self = (MessageQueryTester*)malloc(sizeof(MessageQueryTester));
  new(self) MessageQueryTester();
  
  return self;
};

2) Just use the regular new operator:

//create …
Ancient Dragon commented: great stuff :) +17
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

I agree with firstPerson. One of the biggest hurdles for many seems to be the math involved in doing 3D graphics. Don't underestimate how much math permeates almost all areas of 3D graphics programming. If you are not comfortable / able / interested in the math that you have to do in this field, you will struggle. I would say you would need 1st year college math to be comfortable doing 3D graphics, if you have less than that, be prepared for a rather steep learning curve to climb.


>>possibly a simulator of a solar system.

I actually did something very similar to that (a bit simpler) a while back. At that time, I had, like you, dabbled for a year or two with C++ programming (Delphi actually, but it's pretty much the same), and I was only sophomore-year in high school (which means pretty much a negligible amount of math knowledge). It took me a while to get it working, but I learned a whole bunch from it. So, yeah, it is certainly possible, but your mileage might differ, of course.

Just an idea, have you thought of implementing a particle system? This is a simple project and it's fun to do. You also seem interested in simulation and a particle system is essentially that, it's a program that simulates the motion of a large number of particles. The nice thing with that is that you don't have to do rotations or …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

I guess so, broadly speaking.

However, a game engine would usually be more generic, as opposed to specific. I would be reluctant to say that any computer game is also a game engine. Like a car engine, you provide the decorations (exterior and interior) and the engine drives it. I like to think of game engines in the same way. Most game engines are built such that you provide it with some code for the game logic (specific to the game you want to do), some models, sounds and images and stuff, and the engine makes all this come to life. So, in general, a game engine is just a set of tools (for programmers) that are integrated together and perform all the generic tasks that any game (within a certain category of games) would need, such that you only have to make cosmetic changes to create a new game.

The kind of things a game engine would do might include: rendering a 2D/3D environment, processing user-inputs, simulating physics, managing the game-data (models, images, sound effects, etc.), managing network play, etc. Of course, the level of genericity will change from one engine to another but most will allow quite a lot of customising.

So, of course, if you have software for one game, and it is reasonably well programmed, that you can certainly consider that the more central piece of it is a "game engine" for that very specific kind of game you did. But the design …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Shouldn't the Patch class hold a pointer to the image to which it is a patch of? It would make a lot more sense if you had the Patch class to act as a view of the image. What is a Patch if it is not a sub-image? If the Patches would act as sub-images, you could simply visit all their pixels as you would when visiting all the pixels of an ordinary image. If you do that, I see no reason to pass the Image pointer down to the patch traversal algorithm, because that pointer would be encapsulated in the Patches themselves. And to answer the question, no, I don't think it is a good idea to pass down the image pointer, if that wasn't clear enough.

I think you do need to take a step back from coding and seriously think about your design.


As for your latest question about "virtual function templates", well you cannot do this. You would have to have a base-class for all you "pixels". Personally, I think that would be crazy. At this kind of algorithmic level, you will have to either give up on trying to get a flexible generic implementation, or give up on relying purely on object-oriented programming (I mean, on the idea of using virtual functions and base-classes as the central mechanism for polymorphism). In other words, you need to implement all this algorihtmic code using templates and generic programming techniques, otherwise, with …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>The reason that I don't want an "image" type output that stores the values is that I need to sort them.

Well, when I said:
"This way, you don't have to worry too much about whether the visitor's output is a single value, an image, a pixel, a vector of float, a bunch of heterogeneous data, etc."
The important part of this sentence is "et cetera", meaning just about anything else you can think of. I suggested creating a few special visitor classes for some of the very important cases, that is, an accumulator (output = scalar value) and a filter (output = another image), but it does not mean all visitors have to be of one of the two types, because the design of the traversal algorithms shouldn't require them to be, in fact, shouldn't require them to be anything more than a Visitor (a fundamental principle of software engineering is the "principle of minimum requirement").


As for rubberman's point on UML, I totally agree that you need to spend a lot more time designing the software then you spend time actually coding it. However, I'm not a big fan of UML, but that is probably just because I never encountered a UML tool that was satisfactory to me (they either lack expressivity or they lack clarity). I would be glad to hear rubberman about what software he would recommend for that, if any, because I usually do my UML-like design with the …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Are there any other tricks to try down this road?

Yes.

First, to avoid the multiple presence of the base-class ImageBase, you must use virtual inheritance. Your problem here is actually called the "dreaded diamond" and is easily solved with virtual inheritance. Ideally, however, the CustomImageBase should not inherit from ImageBase because it is just an additional interface for your classes.

Second, to solve the casting problem: if CustomImageBase doesn't have ImageBase as a base-class how do you store it in the container and how to you retrieve it from the container? The answer: cast it. You will need to use dynamic_cast to cast from CustomImageBase to ImageBase or vice versa. Ideally, of course, you should just store pointers to CustomImageBase in your container instead and avoid all the stupid casting back-and-forth. If you use shared-pointers (as you should), then it is even easier to have two containers, one with shared-pointers to ImageBase (for use in the rest of the library) and one with shared-pointers to CustomImageBase (for use in your special part of the library), or as weak-pointers.


>>I can't know the types of these images before hand, as they are read from the files the users selects. This seems like a pretty common case to want to handle, no?

Sure it's very common, but you can generate all the code for each image type before-hand, can't you? Here is the typical way I would handle this problem (say I …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The preferred mechanism to use boost.variant are visitors. Your example would translate to:

#include <iostream>
#include <vector>
#include <boost/variant.hpp>

class ImageBase { };

template <typename TPixel>
class Image : public ImageBase
{
public:
  TPixel GetPixel() const 
  {
    TPixel a = 3; return a;
  }
};

struct OutputVisitor : public boost::static_visitor<> {
  template<typename TImage>
  void operator()(const TImage* image)
  {
    std::cout << image->GetPixel();
  };
};

int main()
{
  std::vector<boost::variant< Image<int>*, Image<float>* > > images;

  images.push_back(new Image<float>);
  images.push_back(new Image<int>);

  boost::apply_visitor( OutputVisitor, images[0]);
}
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You're trying to mix a compile-time mechanism (overloading) and a run-time mechanism (dynamic dispatching). They can't mix (at least, not that way). You have to choose.

You can achieve run-time dispatching based on the type, that is dynamic dispatching. The native mechanism for doing that is the use of virtual functions. If you can't use that, you can do it externally with a dispatching function that uses the RTTI (Run-time Type Identification) via either uses of dynamic_cast or with the typeid() operator. Generally, you only need to do this if you are implementing a double dispatching mechanism. Double dispatching is notoriously difficult to implement in a scalable way, I think the quote of Alexandrescu says a lot: (talking about double dispatching) "I am convinced there is a solution to the inheritance problem. But, alas, writers of books have deadlines, too.".

However, at compile-time, double dispatching is a piece of cake, overloading rules and Koenig-lookup solves the problem for you, all you have to do is provide the required overloads (and/or template specializations).

Of course, if you have overloads that take a pointer to derived classes and another version that takes a base-class pointer, then the most derived class version will be selected if the function is called with a pointer to an object of the actual type of the object it points to (.. you know what I mean..). So, the problem becomes to store an "array" of objects of heterogeneous types.

First thing …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>If so, to apply more than once visitor which each computes a different difference, would you do something like this:

No offense, but that's a terrible idea. Not necessarily dangerous, but inefficient and ineffective.

If you need to do many things with each pixel / pixel-pair / patch / patch-pair, then make a composite visitor, which is, in turn, a visitor as well. It's that simple. Basically, a composite visitor would just be a visitor class that is also a container of visitors. For each element(-pair) that it is given, it traverses all the visitors that it contains and applies them to the element(-pair). You can also have special composite visitors with a special set of visitors, the possibilities are endless. So, your example would be more like this:

vector<PixelPairVisitor> visitorsToApply;
CompositeVisitor all_visitors(visitorsToApply);

image.VisitAllPatches(all_visitors)

// Extract the accumulated values from the "visitorsToApply" vector (or the composite visitor).

This is more effective because you can treat any kind of visitor just the same, in other words, it scales much better to the development of various kinds of visitors. To achieve this, you have to realize that you CANNOT channel the "output" of the visitors through the image-traversal function (the "VisitAllPatches" function for example), because this will almost inevitably cause you to make an assumption about the nature of the output of the visitor (unless you have some really good template meta-programming kung-fu skills under your belt). Don't make assumptions that restrict the applicability of your methods unless there …

daviddoria commented: Again, thanks! +12
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Is there a reason for doing that, as opposed to writing a AveragingColorPixelVisitor, and an AveragingGreyPixelVisitor?

Yes. As you said, "the logic has to be duplicated anyways", well, not exactly. From the outside world, the logic achieved by the visitPixel(GreyPixel) and visitPixel(ColorPixel) is the same (i.e. accumulates the given grey value to the average grey value), but the implementation of it is different when given color pixel because the grey value (average or max or whatever) has to be computed from the color values. The idea here is "encapsulation", that is, there is one logic (accumulate the average grey value) but multiple implementation details (grey or color pixels), so, you encapsulate the implementation details in one functor class that represents one unique logical operation.

Doing this also has practical benefits (these design practices are not there just for show). In the example I gave, one thing you would have to do, if you had two visitors (e.g. AveragingColorPixelVisitor and AveragingGreyPixelVisitor), is to provide some switch code to detect the kind of pixels in the image and provide the correct visitor:

//The averaging algorithm for the grey values of a grey-value image:
template <typename GreyImage>
typename boost::enable_if< is_grey_image<GreyImage>,
float >::type computeGreyValueAverage( const GreyImage& im) {
  //create an averaging visitor (and accumulator):
  AveragingGreyPixelVisitor visitor;
  //call the core algorithm:
  visitAllPixelsInRegion( im, entire_image_region(im), visitor);
  return visitor.getAvgGreyValue();
};

//The averaging algorithm for the grey values of a color image:
template <typename ColorImage>
typename boost::enable_if< is_color_image<ColorImage>,
float >::type computeGreyValueAverage( const ColorImage& im) { …
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Is there any reason you would want to write your own RTTI system for use in your code, when there already is one in C++?

Empirically, there most by since there are a number of libraries that rely on some form of a custom RTTI (some build upon the C++ RTTI and others are built from scratch). My library (link below) has a custom RTTI, whose original motivation was to allow for casts on objects from a different module (dll, exe, etc.) which C++'s RTTI is not capable of doing (nominally), also to remove compiler-dependence on the identifiers used for the types to allow for more portable serialization code.

Another possible reason is just to tweek the feature-set, the C++'s RTTI is a vanilla solution (i.e. a "one-size-fits-all" solution). As with most such solutions, they rarely fit perfectly for anyone, and when the fit is too bad, people create their own solution. For example, some find the C++ RTTI to be too heavy-weight for light micro-processor applications and they only require dynamic casting, in this case, you don't need the RTTI, you just need a simple virtual casting function. On the other hand, some find the C++ RTTI lacks features (e.g. for reflection, for serialization), and end up creating their own RTTI for the purpose of adding those features.

Then, you have compatibility and portability issues that come from the fact that the details of how compiler-vendors should implement the C++ RTTI is left unspecified, and thus, …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>You are suggesting that the differences should NOT be contained in the PatchPair, right?

Yes.

>>By this folding/accumulation you are suggesting, how do the differences stay associated with their generating PatchPair?

By an associative container, by a multi-index container (boost.multi-index), by a simple std::pair< float, PatchPair> , by a custom POD type, or whatever. Fundamentally, this is a multi-index structure and should probably use that if you need to associate the diff-values with the patch-pairs, but you shouldn't require this association because it can be a costly one and may not always be necessary. The important thing is that the patch-pair that is the input to the algorithm that computes the diff-value isn't bound to the algorithm that computes its diff-value, because that makes no logical sense and is only going to be hard to deal with programmatically.


>>Can you suggest a good reference (book/website) for this type of thing?

For references on accumulators (which is a very simple concept once you see it), I would guess Boost.Accumulator is a good example library for that. Fundamentally, many uses of lambda-expressions (C++11) that use closures make the lambda-expression act as a simple accumulator.

As for libraries that use visitors, I suggest you look at the design of the Boost.Graph library (BGL), more specifically, at the graph traversal algorithms like Dijkstra, A* and so on, they are all built upon three fundamental traversal algorithms (breadth-first, depth-first, and uniform cost search). And I mean, the …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

@m4ster_r0shi:

That is definitely a better test (with static analysis in the second case being impossible or at least very hard for most compilers). And the results are as expected. Without optimizations, the compiler inlines nothing and thus, the small performance penalty remains with the policy case because of the extra function call (jumps to Run() and then to Operation(), while the dynamic polymorphism case reads the virtual table and jumps straight to the useful function). With optimizations, the policy functions probably get inlined in the switch-case, so all you get is the time to evaluate the random-numbers, the switch-case (with poor branch-prediction), and the addition operation, while the dynamic polymorphism case adds only the overhead of a function call.

However, in reality, in larger projects, the performance difference becomes a lot harder to evaluate and it is expected to be a lot more significant because of the more important issues such as cache misses, branch-prediction, and memory locality. A good example are typical object-oriented (with virtual functions) matrix libraries that are much much slower than equivalent template-based matrix libraries, I mean orders of magnitude slower.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Wow, this is a bit messy, to say the least.

Your problem is with the mixed responsibilities more than any other issue (templates, non-templates, base-classes, etc., these are all just details). From my understanding, the overall purpose is to perform transformations which are characterised by the following:
- Input
- Output
- Map
- Iterator
- Fold

For example, taking the difference between two patches means that you need a way to iterate through the pixels of the patches, then map the two pixel values to some difference value, and finally fold all those differences somehow to obtain a single output that represents the overall difference between the patches.

Your SelfPatchCompare thing has a similar pattern, it takes a patch and an image as input, needs a way to iterate through the patches of the image, then map the patch-pairs to some difference value (patch-difference), and then fold those differences into a single overall difference value.

What I'm trying to emphasise here is that you shouldn't be asking yourself where to put what data or which inheritance-scheme makes more sense, but you should ask what is the functional skeleton of your problem and where are its knots (or joints, or atomic elements). This is how you get to modularity, and once that is done, static vs. dynamic or how to shape the inheritance tree are usually self-evident and trivial to solve with a little programming know-how.


One concrete …

daviddoria commented: Mike has gone above and beyond yet again! +12
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

With compilers in general, we often talk about the front-end and the back-end. The front-end is the program that parses the source code, verifies all the grammar and syntax rules, and basically produces a translation of it in some intermediate language (not human-readable but readable for the back-end). The back-end takes the intermediate source code and performs most of the optimizations and then compiles to native machine code. So, the back-end is usually common to an entire compiler suite (like GCC, ICC, Clang, etc.), and then there is one specific front-end for each programming language supported by the compiler suite.

Examples:
- Borland's Delphi and C++Builder compilers share the same back-end (meaning you can also link C++ object files ".obj" with Delphi compiled units ".dcu" together).
- All GCC compilers (C, C++, Objective-C, Ada, Fortran, Java, etc.) share the same back-end, but with different front-ends.

A prominent back-end is LLVM which is used by the Clang front-ends and other compilers.

Prominent front-ends are those of EDG, which are used by Intel and Comeau.

Whatever front-end, parsing the C++ language is not an easy task, because its grammar is complex and context-dependent. Recursive descent parsers are used with plenty of modifications to really get reliable and accurate parsing. There are also tools for generating parsers, including YACC and Boost.Spirit.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

@stereomatching:
I totally agree.

Definitely, there are big myths about C++ circulating. So, reiterating for the record:
- C++ is NOT an object-oriented programming language (whatever that means), it is a language with direct, native support for multiple programming paradigms.
- C++ is NOT necessarily slower or fatter than C, benchmarks have proven that fact, for example here where C and C++ performance are usually within each other's error margins (and at the top or near the top, alongside Fortran and Ada).

As for the programming FAQ thread linked above, well, the author repeats these myths mostly as a symptom of his pure-OOP / Java biased judgement. Be indulgent to the fact that Java programmers live in a bizarro world where pure-OOP is the holy-grail of programming style, where only an OOP solution can be the best solution to a problem (or the new trend of AOP), where C++ only matters in so far as it compares (defavorably according to them) to Java/C# which is a comparison that can only be made if you assume that good C++ code has to stick to pure OOP and thus, pay a senseless performance and/or code-bloat price just for the ideological satisfaction of having written the purest OOP code possible. I pity those who are brainwashed in that way.

A simple way to summarise the philosophy of C++ is this (which I often repeat):
In C++, you pay for what you _get_,
but …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>i can say for sure that it will work with internet

That's pretty vague. Surely, for internet-related programming, C/C++ aren't good choices. Although I am of the opinion that no education in programming is complete without being at least functional in C++ programming (because it is so central to the entire programming world), I have to say that if you have a particular area of work in mind and if the central aspect of that area is "the internet" than C/C++ are not very likely to be the languages you will end up using in that area of work.

You have to understand that there are three main lines of programming work in "the internet". First, you can do "networking", like programming servers, routing algorithms, and similar programs which are generally running on some server (and some clients) and works "under-the-hood" to manage data transfers and synchronizations and so on. For these types of applications, be prepared to work in UNIX environments (or Linux, or Solaris), and the more likely candidate languages to learn are Perl and Python, with some basics in C and then some web-scripting languages. Second, you have "internet applications" in the sense of desktop applications that makes heavy use of some underlying internet (and often also a database) connection with a server. For these applications, languages like Java and C# are the ones you will be most comfortable with and are most likely to encounter in that line of work. Finally, you have "web …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Is it really that hard to google "calling convention"? The first three links gives all the info you are looking for.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

There are a number of things happening here that make this test flawed.

Generally when people make performance arguments between static versus dynamic polymorphism (i.e. based on templates or based on virtual functions, respectively), the thing that makes all the difference is whether the mechanism is static or dynamic. So, any test to compare the two is void if you make it trivial enough that the compiler can easily resolve the dynamic case back into a static one. I'll explain.

When the polymorphism is realized at compile-time (statically) then there are several advantages, i.e., additional things the compiler can do to speed up the execution. Amongst those optimization opportunities are these main ones:
- Replace the function call by an inline expansion.
- Do more aggressive copy-elision for the parameters and return values.
- Arrange the compiled code in the object-file such that related functions (related by mutual calls) are close together, minimizing cache misses.
- Work in-place and without indirection with the "this" object in member functions (when that object is stack-based and the call is inlined).
- etc... there are more I'm sure, I'm no expert in optimization techniques.

All these optimizations are clearly only possible because the compiler has knowledge of both the call-site and the called function at compile-time (and because the function is often uniquely tailored (templated) to the specific call-site making it an obviously good candidate for inlining).

So, in order to compare code that …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

What you are describing is just a typical commercial license, with the only difference that you are not charging a price for getting the program (i.e. freeware). But that's still a commercial license, you can charge the price you want for any of the three distributions (app, libs, or source), including zero (free). A generic freeware license should work fine for you.

A simple google search would turn up a few good example license:

The freeware license used by Adobe for their "Acrobat Reader" application which is distributed for free (to read pdf files) but the libraries and sources are protected by copyrights.

The freeware license used by Eltima, which is a simple typical example of a freeware license which says that the user can use the software freely, install it anywhere he wants to, give it out to people for free (except for small fee to cover the cost of making the copies or whatever, e.g., the cost of buying a writable CD), but is not allowed to make any money off of distribution or re-packaging it. It also forbids reverse-engineering and all that stuff, i.e., basically protecting the libs and sources (and the intellectual property on that).


As for the license on your libs and sources, cross that bridge when you get to it. Just make a note on your website that you are open to making a licensing deal to distribute your libs or sources, and wait …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Is it possible to write a c++ compiler in c++ ?

Well, the steering committee of GCC believe so. I don't know of any compiler that is entire written in C++, but it is certainly possible. The only problem is that compilers need to be rock solid, meaning that you cannot just throw away decades of robust C code just to satisfy some C++ zealots. But, some compiler writers like GCC are now allowing C++ code to be added to the existing C code, and I think there is also talk of creating a separate development branch to port the whole thing to C++ (at least, make all the C code compliant to C++98, as opposed to ANSI C). Other than that, I would imagine some compiler vendors use C++ at least for some parts of their compiler's code (e.g. the front-end), but I don't know of any that is known to be entirely in C++, and that really doesn't matter much.

>>Its bootstrapping, right ??

Sort of. You can already boot-strap GCC. When I compile the latest GCC version from source (which I do every month or so), I compile it with the GCC compiler I already have. The build script that GCC uses will compile then entire code of the C compiler 3 times: first with any C compiler already installed on the computer, then once with the newly compiled GCC C compiler, and then again with the newest compiled GCC C compiler. …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>However, I guess I don't understand why the object that was getting passed was const?

My guess is that the STL implementation of std::sort wraps the "compare" object inside another functor that takes either const-references or const-iterators. So, the only viable options when defining a comparison functor is to use either const-reference or value parameters, which makes sense from a const-correctness point-of-view, a comparison function should not modify its operands. STL uses const-ness pro-actively in these situations, I suggest you do the same.

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

Well from the link, the assignment operator requirement is only for "output iterators" where the expression *it = a; must be valid. BTW, the iterators for the std::set container are not output iterators. So, that shouldn't be a problem.

But iterators are not all, you need to watch out for what you can do with the container. People often say that the value type of any container has to be CopyAssignable and CopyConstructible. Well, that is an oversimplification of reality. If you want all operations to be possible with a container, then yes, you need to meet those requirements. But the operations that actually require copy-assignable value-types are actual not that many, especially for std::set (whose philosophy is that its key-values are to be constant after the initial insertion). For std::set, the only operation I could find that really require copy-assignable (or move-assignable) values is the assignment operator of the container itself.

This argument goes for the other containers, the C++ standard specifies the requirements on the value-type on a per-function basis on the containers (e.g. if you want to do insert() in a vector container you need a MoveConstructible and MoveAssignable value type, etc.). This makes sense since containers are class templates for which only the functions that are used are actually instantiated, so, the requirements on the value type is just the addition of the requirements of all the functionality of the container that you actually use in your code. Generally, all the "link-list" or "tree" …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

The main problem, of course, with the code you posted is that the indirect_iterator class implements the assignment operator in terms of an assignment operation on the pointees, not the pointers. Because indirect_iterator was made with the assumption that it should behave exactly as if the iterator was an ordinary iterator in a container of values (not pointers), it has to implement assignment with deep copies. Evidently, if your pointees are const objects, then you cannot do any operation that would require the iterator's value-type to be non-const.

What you would need is a sort of hybrid indirect-iterator that would dereference the pointers for all "value-access" operations, and that would move the smart-pointers around whenever doing move / copy / assignment operations. The problem is that these are not distinguishable because they both go through the same operator, the dereference operator on the indirect_iterator class. For instance, the standard sort algorithm is most likely based on a swap operation like swap(*it1, *it2) which is a data-move operator that relies on the dereference operator of the iterator, then, it probably also calls compare(*it1, *it2) which is a data-access operation, but from the point-of-view of the implementer of the iterator class, these two operations cannot be distinguished at all.

The only way to solve this is to use an indirect compare operation and a normal iterator (to the pointers) for the sort operation. For other operations in which you want to have an indirect-iterator, just use make_indirect_iterator from outside your …

daviddoria commented: Thanks for the thorough analysis. +12
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

If you make functions that are re-entrant (or almost pure-functional) then you don't have to worry about anything. The main characteristic of a re-entrant function is that it has no dependence whatsoever on data from outside the function (excluding the input variables of course, and read-only access to global (quasi-)constants), and has no side-effects (it generates some outputs from the given input variables, and that's it, it doesn't modify any global variables or anything of the sort). In this case, once the function is provided with its input variables, it can, by definition, operate from start to finish without affecting anything else in the application or without being affected by any changes in the application's state. This implies that you don't have to worry one bit about using this function in a multi-threaded environment.

The fact that two or more threads are executing the same function at the same time makes no difference, each thread has its own execution stack for the function, and thus, each execution is entirely separate from one another.

What you have to worry about is SHARED DATA.

This innocent-looking function that caches the fibonacci sequence is a typical example of a hidden side-effect:

int GetFibonacciNumber(int i) {
  static std::vector<int> seq{1,1};
  while(seq.size() < i)
    seq.push_back(*(seq.rbegin()) + *(++seq.rbegin()));
  return seq[i];
};

Here, the fibonacci sequence is being cached in a static vector which is unique for all instances of the function and is thus a data element that is shared between threads that …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

I'm not an expert with boost.spirit, but I don't think that it makes much sense to specify a delimiter which has "any number of spaces" as in the delimiter generator expression (*(karma::space) << ',' << *(karma::space)) . This is likely to be the explanation for the infinite loop (probably the star (or "any number of") isn't meant to ever be used in a generator expression, but compiles nonetheless and causes an infinite loop if used as a generator). So, I would replace it with either (karma::space << ',') or (',' << karma::space) (or with two spaces).

From the examples on the boost.spirit webpage it also seems that the generator expression given to the "generate_delimited" function should be one that has an "any number of" type format over the attribute to be outputted. In other words, it seems that the expected behaviour of your code would be to output only the first number in the sequence, and that this generator would be worth a try in case it is so:

karma::generate_delimited( inserter, '(' << karma::int_ << ')' << *('(' << karma::int_ << ')'), (karma::space << ',' << karma::space), r);
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

>>Does it mean that all the variables, classes and functions are members of "main".

Only variables. So, yes, in principle, if you don't have any global data, then everything (all objects, but not classes or functions) is somehow under the scope of the main() function. But that's just because the main() function is the program.

>>So, if i want to access the the variables from other thread or form, I should use "main->StringVariable"?

No. main() is a function like any other, you cannot, from outside, access its local variables, because that simply cannot make any sense, and the compiler won't allow it, of course. You cannot access the variables of main. If you want an object that you create to have access to a variable of the main-function then you need to give it access to that variable by providing it with a pointer or reference to that variable.


>>If lets say I start a thread in "main" and I want to access "main->StringVariable" from that thread, I can't directly use "main->StringVariable" in that thread right because "main" is not a member of that thread.
>>Then, how should I do it?

You can't and you shouldn't. When you say "I start a thread in main and I want to access main->StringVariable", that's where things go wrong. You cannot make such a grave decision so casually, that's my main point. Especially in a multi-threaded environment. In this specific case, either StringVariable shouldn't be …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

What you are describing is a classic MVC (i.e. "Model-View-Controller") design pattern.

If you look at what your application is supposed to do from start to finish, it will look something like this:
1) Load some configurations describing how to connect to the data-server.
2) Establish a connection to the server.
3) Download all relevant information from the data-server.
4) Create a Viewer-Controller to display and modify the data somehow.
5) Buffer all the changes to the data.
6) Upload the data to the server every hour or so.
(When finished)
7) Destroy the Viewer-Controller.
8) Disconnect (log-out) from the data-server.
9) Terminate the application.

To me, it is pretty obvious that the Viewer-Controller (whether separate or together) require the existence of the "Model" to function (the "Model" in this case is the data streamer that buffers the data from the server). However, it is clear also that neither the Viewer nor the Controller should own the Model (the Model is created independently of the Viewer and Controller). This also opens the door to having multiple Viewers or Controllers, which can be a very nice feature.

It is also clear that the existence of the Model is not tied directly to the life-time of the program, it is tied to the availability of a connection to the server (or the necessary configuration to set-up one). You need to first collect the necessary configuration information before …

mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster

You should start by finding the total differential of your formula. Then, computing it is a trivial matter with minimal knowledge of C++.