Who can join me in a new open source project?

Pages: 12
May 12, 2011 at 4:20pm
Hello.

As some of you know, Computergeek01 and a few others developed an interest in a project I proposed as a mere exercise: Create a library of classes that allow for easy calculation of values with units such as meters, seconds, Newtons, Pascals, calories, BTU's, litters, US Barrels, UK barrels, etc. It is a dear project idea I have had for some time now.

I have some basic classes, and I think the idea is solid, but I am not that good in C++, so I am having a bit of a hard time getting where I want to be. Plus, the project itself is not a small one.

So I was thinking this would be the best way to see it through. Anyone out there interested? Anyone out there is or have participated in one of these (I haven't)? Where should it be posted? I like Microsoft's www.codeplex.com, but sourceforge is also popular. Any other?

Your input is appreciated.
May 12, 2011 at 4:22pm
What about github.com? I think this is what it's for. They have subscription accounts. But I think you can have a few projects with a few members for no charge provided that the projects are public on their website.

EDIT: I stress that I haven't used it, so I don't know if it's any good. I was just pointing it out as an alternative :)
Last edited on May 12, 2011 at 4:22pm
May 12, 2011 at 4:24pm
... and sourceforge.
May 12, 2011 at 4:27pm
I like SVN as source control. Do you guys know what is used in github.com and sourceforge.net?
May 12, 2011 at 4:37pm
From the github site:
At the heart of GitHub is an open source version control system (VCS) called Git
May 12, 2011 at 4:43pm
closed account (zwA4jE8b)
May I join?
May 12, 2011 at 4:45pm
Sure you can, if you can cope with it.

I have a very basic source code here: https://ideone.com/XCVkX.

It has a few misconceptions, plus I have evolved the design a bit. It is no easy stuff, don't be confused. Check it out first, then decide. Sounds good?
May 12, 2011 at 5:01pm
So I can tell you a bit about one of the problems: I have a LengthUnit class that serves as base of all units like MeterUnit, FootUnit, InchUnit, etc. But let's face it: I don't want people redefining what a Meter is, right? So I added private constructors and then a single static const field in each class: FootUnit::Foot is an instance of FootUnit that represents a foot.

But prefixes (kilo, Mega, Giga, deci, centi, etc.) makes things more complex. To further explain:

A particular instance of a Length class (that contains a double value and a polymorphic LengthUnit* unit) may alter the unit adding a prefix because maybe they want kilometers. I don't want the developer using the library to be concerned about the storage of this new instance of MeterUnit (which will be copy-constructed from MeterUnit::Meter). The developer should be able to say something like:

1
2
Length myHeight(1.74, MeterUnit::Meter);
myHeight.ConvertTo(MeterUnit(MeterUnit::Meter, Prefix::milli));  //convert to millimeters 


They have to create a new instance because MeterUnit::Meter is const and a prefix cannot be added.

Internally, all Length objects save a pointer of type LengthUnit because a reference cannot be changed, and it has to be a pointer or reference because it is polymorphic. Finally, the question: Where does the new unit is to be stored? Note that in the example above I am using a new instance of MeterUnit, but I could have used a const like FootUnit::Foot.

Or maybe I have been thinking this the wrong way?
May 12, 2011 at 5:28pm
closed account (zwA4jE8b)
I fixed the output problem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Length : public Dimension<LengthUnit>
{

        //Constructors
public:
        Length() : Dimension(0, Length::UnitType::StandardUnit)
        { }
        Length(double value, Length::UnitType const &unit) : Dimension(value, unit)
        { }
		friend std::wostream& operator<<(std::wostream &op1, Dimension& op2)  //CMFS EDIT
		{
			return (op1 << op2.GetValue());
		}
};


removed

1
2
3
4
5
6
//template<class U>
//std::ostream& operator<<(std::ostream &op1, Dimension<U> const &op2)
//{
//        op1 << op2.ToString();
//        return op1;
//} 



I am 1.74 tall.
The doorway is 6.5 high.
Press any key to continue . . .
Last edited on May 12, 2011 at 5:29pm
May 12, 2011 at 5:32pm
So, did you like the project? What do you think about the source code? Difficult? Can you do it? BTW, GetValue() is public, so no needs for friends.

Also, I was hoping to be able to implement operator<< just once in Dimension<T>. Can it be done?

EDIT: I just noted something: the output should have read "I am 1.74 m tall." Operator<< needs to output .ToString() not .GetValue().
Last edited on May 12, 2011 at 5:34pm
May 12, 2011 at 5:35pm
closed account (zwA4jE8b)
I am not sure, because an instance of Lenght is being declared.

I will try out a couple things and see if I can get only one operator<< in the dimension class and let you know.

I do like it. I have not gone through all of it yet but It seems really cool.

The biggest change is the wostream because in Unicode it needs the wide stream
Last edited on May 12, 2011 at 5:36pm
May 12, 2011 at 5:37pm
closed account (zwA4jE8b)
Also, at least when I compile it the friend is needed. Something about stream overloading requires it. At least in the context I wrote the function.
May 12, 2011 at 5:44pm
Aha! I forgot about wostream. My bad. See the beginning of the source code. Add a tostream typedef equivalent to tostringstream, please, and then write the operator using the generic tostream type. That will serve both ANSI and Unicode builds.
Last edited on May 12, 2011 at 5:45pm
May 12, 2011 at 6:03pm
closed account (zwA4jE8b)
I did a little reading and it look like even though you can declare the overloaded operator in the base class we will need to repeat the work for the derived class. So it would be repetative.


It looks like the overloaded << will have to be in each class that needs to use it.
And in this case the friend is needed.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#ifndef tstring
#ifdef _UNICODE
typedef std::wstring tstring;
typedef std::wistringstream tistringstream;
typedef std::wostringstream tostringstream;
typedef std::wostream tostream;
#else
typedef std::string tstring;
typedef std::istringstream tistringstream;
typedef std::ostringstream tostringstream;
typedef std::ostream tostream;
#endif // _UNICODE
#endif // tstring
 
//Some useful typedefs from the Windows SDK.
//Since these are defined in WinNT.h, I'll take the chance of using this condition:
#ifndef _WINNT_
#ifdef _UNICODE

..........................


class Length : public Dimension<LengthUnit>
{

        //Constructors
public:
        Length() : Dimension(0, Length::UnitType::StandardUnit)
        { }
        Length(double value, Length::UnitType const &unit) : Dimension(value, unit)
        { }
		friend std::wostream& operator<<(std::wostream &op1, Dimension& op2)  //CMFS EDIT
		{
			return (op1 << op2.ToString());
		}
};
 
class Time : public Dimension<TimeUnit>
{
        //Constructors
public:
        Time() : Dimension(0, TimeUnit::StandardUnit)
        { }
        Time(double value, Time::UnitType const &unit) : Dimension(value, unit)
        { }
		friend std::wostream& operator<<(std::wostream &op1, Dimension& op2)  //CMFS EDIT
		{
			return (op1 << op2.ToString());
		}
};


I will see if there is a way around it, but I am not too optimistic. But hey, This works!!!
Last edited on May 12, 2011 at 6:11pm
May 12, 2011 at 6:14pm
closed account (zwA4jE8b)
I noticed there was no MinuteUnit....

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MinuteUnit : public TimeUnit
{
        //Constructors
private:
        MinuteUnit() : TimeUnit()
        { }
 
        //Public Interface
public:
        virtual bool IsStandardUnit() const { return true; }
        virtual LPCTSTR GetName() const { return _T("minute"); }
        virtual LPCTSTR GetSymbol() const { return _T("m"); }
 
        static const MinuteUnit Minute;
};

const MinuteUnit MinuteUnit::Minute = MinuteUnit();



What does this line do? I do not understand it.
const MinuteUnit MinuteUnit::Minute = MinuteUnit();
May 12, 2011 at 6:56pm
Apparently, in C++ I cannot initialize a static variable in the same line as its definition. This is why I had to put the singleton variables' initialization outside of their corresponding classes.

The specific line you show creates a MinuteUnit with the default constructor and then assigns it to MinuteUnit::Minute. Depending on compiler optimization, that would be a call to copy-construction or not. But it really doesn't matter much, as this happens before entering main() and it happens only once.
May 12, 2011 at 7:59pm
Ok, I have managed to get another version that compiles OK under my VS. Again, ideone.com says weird things like Length doesn't have a field called Dimension. The compiler they use sucks!

https://ideone.com/XCVkX

Check it out. This one has Dimension<T> comparison operators and I was able to create the global operator<<() function for streams! BTW, no friend was required for it. I was able to fix it thanks to your keen observation that I needed wostream.

Let me know your inputs.

BTW, I think I solved the problem about ConvertTo(). Internally, all Dimension<T> objects now hold a pointer to T*. The constructor receives the pointer and assumes responsibility for deleting it in the destructor. On the other hand, subclasses of Dimension<T> receive const& unit objects and call a new method I added to class Unit, which is Unit::Clone(). It is virtual and to get the correct clone, each unit class must override it. In Unit it is public, but in derived classes I made it protected. Does this sound like a decent solution?
May 12, 2011 at 8:51pm
CreativeMFS, now that I think I got my problems solved, I took a look at your posts.

For the operator<<, please see updated code. The one global operator function there is working fine.

As for MinuteUnit, yes, there are many units missing. All acceleration units, all force units, all pressure units, all energy units, etc. No worries about that, hehe. I also see that you are saying MinuteUnit is the standard unit of time. It is not. It is the second. Only SecondUnit returns true from IsStandardUnit. And you also forgot to return the correct factor from the virtual GetFactor(). Any unit must return the conversion factor as "X std units per this unit". Since the second is the standard unit of time, MinuteUnit must return 60, since "60 seconds per minute" is the correct conversion factor.
May 12, 2011 at 10:19pm
Let me start off by saying I'm so glad you ran with this, it had actually had slipped my mind for the last two days.

First thing I want to throw my vote in is that we plan on breaking this down a bit later, it's fine for now so that everything is on one page but it clusters together.

Are we ignoring the half dozen warnings and\or errors I get when I compile so far(MingW)? Because a lot of those can be fixed with static casts.

EDIT: Beacause of what webJose said in one of his posts and because I seem to be getting odd errors on MingW are we agreeing to use cl? Or which compiler do you guys use? I should note that even though I am familiar with Cygwin I dislike using it just to compile C++ with GCC.
Last edited on May 12, 2011 at 10:25pm
May 12, 2011 at 10:35pm
By the way the error you're getting that says "Length doesn't have a field called Dimension" is because it is destinguishing between the inherited "Dimension<LengthUnit>" constructor and you just using "Dimenstion" it's an unhelpful error but I was getting it to until I changed Line 621 from:
 
Length() : Dimension(0, dynamic_cast<Length::UnitType*>(Length::UnitType::StandardUnit.Clone()))

To
 
Length() : Dimension<LengthUnit>(0, dynamic_cast<Length::UnitType*>(Length::UnitType::StandardUnit.Clone()))


EDIT: You seem to make this error repeatadly in the code. I've gotten it to compile by fixing all calls to Dimension to include the correct template name.
Last edited on May 12, 2011 at 10:46pm
Pages: 12