• Forum
  • Lounge
  • Perhaps a proposal for a change in C++ :

 
Perhaps a proposal for a change in C++ : typedef

I am always fully prepared to be shot down by experts on this forum, so I thought I would mention my wee idea here first. Maybe there is a way around this problem that I wasn't aware of.

My motivation for doing this comes from my field of Surveying where there are lots of examples of potential types which consist of a solitary double. Also I was reading one of Bjarne's articles about mission critical systems: would these benefit from making it easier to have very strong typing for function arguments? More about this later.

Now, a use case: There are lots of ways to create a geometric Arc, and we need a way to disambiguate arguments in the constructors. The arguments consist of 2 types: doubles and points. Obviously the easiest thing to do is create structs for each different type, but this is a pain when the object contains a solitary double as in Radius, StartAngle, Angle, EndAngle. It is even worse for the points: Sure, one can invent new classes that inherit from an existing Point class, but it would be convenient to avoid that as well. I am aware of class factory design patterns exist, but am proposing this could be a language feature.

Obviously the existing typedef & using alias don't work for this.

So I am proposing these new syntaxes:

First for simple types
1
2
3
4
5
6
7
8
9
// with a simple type double
typedef class CRadius<double>;

// with assignment
typedef class CRadius<double> = 10.0;

//or this with a constructor
typedef class CRadius<double>(10.0);

which would implicitly create this:

1
2
3
4
//constructor, operators etc not shown, just conveying the idea
struct CRadius {
double radius = 10.0;
}


With this usage:
1
2
3
4
5
6
7
8

CRadius TheRadius = 10.0;

//or this
CRadius TheRadius2(10.0);

CArc MyArc(TheRadius, TheCentrePoint); // constructor call


Also would like to use the variable directly (as if it was a double):

std::cout << TheRadius;

Might need to overload operator() to do this? No arguments means return a value, 1 argument means assign a value.

Now the second case, where the type is an existing class:

typedef class CCentrePoint<CPoint>; //could have a boost class here instead of CPoint

Again, it would have to behave like a CPoint. I guess the implementation would just inherit CCentrePoint from CPoint

Now we could do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
typedef class CRadius<double>;
typedef class CAngleStart<double>;
typedef class CAngleEnd<double>;
typedef class CAngle<double>; // CStartAngle + CAngle = CEndAngle

typedef class CPointCentre<CPoint>;
typedef class CArc(CPointCentre Centre, CRadius Radius);<CPoint>;
typedef class CPointBegin<CPoint>;
typedef class CPointEnd<CPoint>;
typedef class CPointMid<CPoint>; //Snap to midpt on CAD system
typedef class CPointOnArc1<CPoint>;
typedef class CPointOnArc2<CPoint>;
typedef class CPointOnArc3<CPoint>;

//constructors

CArc(CPointCentre Centre, CRadius Radius);
CArc(CPointCentre Centre, CPointBegin PtBegin, CAngle Angle);
CArc(CPointBegin PtBegin, CPointEnd PtEnd, CRadius Radius); // disambiguated now compared to line above. Centrepoint determined by order of begin & end always counter clockwise
CArc(CPointCentre Centre, CRadius Radius, CAngleStart AngleStart, CAngleEnd AngleEnd); // disambiguated now compared to line above
CArc(CPointCentre Centre, CRadius Radius, CAngleStart AngleStart, CAngle Angle); // disambiguated now compared to line above
CArc(CPointOnArc1 PtOnArc1, CPointOnArc2 PtOnArc2, CPointOnArc3 PtOnArc3);

// plus others, especially for 3D Arcs 


Here is a question: Is there another way of disambiguating these arguments?

I guess the implementation of this would be easy enough with template code (although I would probably learn a lot if I had a go).

With the mission critical code Bjarne was talking about, it seems that coders didn't use units (the cause of the problem), and I get the impression things weren't strongly typed either, I am guessing they might have had this scenario (a pedagogic example):

double CalcDistanceToMars(double DistanceFromEarth);

rather than:

CDistanceToMars CalcDistanceToMars(CDistanceFromEarth DistFromEarth);

So, if it was easier to create new types, I am thinking that would be an advantage.

I look forward to all the replies. Cheers

Reference to the Mars project, in the compute less section:

http://www.stroustrup.com/Software-for-infrastructure.pdf

Last edited on
I don't really understand what you're trying to do or what the syntax is supposed to be saying. Do you just want strong type aliases? If so, request that rather than inventing confusing new syntax.
Hi L B,

Thanks for your reply.

I don't really understand what you're trying to do or what the syntax is supposed to be saying.


I wanted a way of creating a new type CRadius which holds a double, rather than this:

1
2
3
struct CRadius {
double radius = 10.0;
}


Do you just want strong type aliases? If so, request that rather than inventing confusing new syntax.


I don't think the syntax is that confusing: it is similar to strongly typed enum.

This code:

typedef class CCentrePoint<CPoint>; //could have a boost class here instead of CPoint

Is saying implicitly create a class named CCentrePoint which is exactly the same as CPoint, just the name is different, hence it is a new type. Another way of putting it: I want to easily clone an existing class.

Maybe the syntax might be different to what I have, but hopefully I managed to convey the idea of what I would like to do.

Do you just want strong type aliases?


Ok, if that is what it is called, just wondering how I go about doing that?

Note that I am requesting to be able to do this easily in 1 LOC, and I alluded to it being possible with template code or a class factory design pattern, but I am also proposing that it might a handy new feature for C++.

Any way, have to run - hopefully this cleared things up a bit.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
template <class T>
class wrapper{
	T value;
public:
	typedef wrapper<T> parent;
	explicit wrapper( const T &value ): value(value){}
	T& operator()(){
		return value;
	}
};

class radius: public wrapper<double>{ using parent::parent; };
class angle: public wrapper<double>{ using parent::parent; };
class pointcentre: public wrapper<point>{ using parent::parent; };
class pointbegin: public wrapper<point>{ using parent::parent; };
class pointend: public wrapper<point>{ using parent::parent; };

int main(){
	arc a(pointbegin(point(1,3)), pointend(point(4,2)), radius(54));
}
Last edited on
TheIdeasMan wrote:
I don't think the syntax is that confusing: it is similar to strongly typed enum.
You and I have very different definitions of "similar" ;)
Last edited on
@ne555,

Thanks, that's awesome - just what I wanted, I knew there was some template magic that could do this !

I will give this a go using the boost point class - I am sure it will be brilliant.

The only other thing is whether anyone wants this to be a language feature?

Cheers :+D
@ne555

Edit: See my later post (& ignore most of this one)- figured out what is wrong.

With the classes that only hold a double, I am having a bit of trouble trying construct and output values.

Have tried a few variations (commented out), but no go.

The value is private in the base class, I thought the purpose of the using parent::parent; was to enable access to it, can you please explain this in more detail? I tried to call the base class constructor, but to no avail.

Also, with the operator()(), does it return a value? Can you please explain how to use this? The way I have it at the moment, it looks like a constructor call.

Do I need to write an operator<< to get some output?

I probably have the concepts all messed up (I have a lot to learn about templates), could you point out what I have done wrong?

Thanks for your help so far, here is the code and the errors.

EDIT: I tried using KDevelop, to see if it was some Qt thing going on, but had similar results.

Another thought: do I need to change the using parent::parent; so it can take an argument?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#ifndef GEOMETRY_H
#define GEOMETRY_H

template <typename T>
class wrapper{
    T value;
   //T m_value;
public:
    typedef wrapper<T> parent;

    explicit wrapper(const T& value ): value(value){}
    //explicit wrapper(const T& value ): wrapper<T>::m_value(value){}
    //wrapper( T value ): wrapper<T>::m_value(value){}
     //wrapper(T value ): parent::m_value(value){}
    T& operator()(){
        return value;
        //return parent::m_value;
    }
};

class angle: public wrapper<double>{ using parent::parent; };

#endif // GEOMETRY_H 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include "geometry.h"

int main()
{
   const double& TheAngle = 45.0;
   angle MyAngle1(45.0);
   angle MyAngle1(); //no error, but how to construct?
   angle MyAngle2(TheAngle);

   std::cout << "MyAngle1 is " << MyAngle1() << "\n";
   std::cout << "MyAngle2 is " << MyAngle2() << "\n";

   return 0;
}


12:25:20: Running steps for project Geometry...
12:25:20: Configuration unchanged, skipping qmake step.
12:25:20: Starting: "/usr/bin/make" 
g++ -c -pipe -std=c++11 -Wextra -pedantic -g -Wall -W -fPIE -DQT_QML_DEBUG -DQT_DECLARATIVE_DEBUG -I/opt/Qt5.1.1/5.1.1/gcc_64/mkspecs/linux-g++ -I../Geometry -I. -o main.o ../Geometry/main.cpp
../Geometry/main.cpp: In function 'int main()':
../Geometry/main.cpp:8:23: error: no matching function for call to 'angle::angle(double)'
../Geometry/main.cpp:8:23: note: candidates are:
In file included from ../Geometry/main.cpp:2:0:
../Geometry/geometry.h:23:7: note: constexpr angle::angle(const angle&)
../Geometry/geometry.h:23:7: note:   no known conversion for argument 1 from 'double' to 'const angle&'
../Geometry/geometry.h:23:7: note: constexpr angle::angle(angle&&)
../Geometry/geometry.h:23:7: note:   no known conversion for argument 1 from 'double' to 'angle&&'
../Geometry/main.cpp:9:19: error: 'angle MyAngle1()' redeclared as different kind of symbol
../Geometry/main.cpp:8:10: error: previous declaration of 'angle MyAngle1'
../Geometry/main.cpp:10:27: error: no matching function for call to 'angle::angle(const double&)'
../Geometry/main.cpp:10:27: note: candidates are:
In file included from ../Geometry/main.cpp:2:0:
../Geometry/geometry.h:23:7: note: constexpr angle::angle(const angle&)
../Geometry/geometry.h:23:7: note:   no known conversion for argument 1 from 'const double' to 'const angle&'
../Geometry/geometry.h:23:7: note: constexpr angle::angle(angle&&)
../Geometry/geometry.h:23:7: note:   no known conversion for argument 1 from 'const double' to 'angle&&'
make: *** [main.o] Error 1
12:25:21: The process "/usr/bin/make" exited with code 2.
Error while building/deploying project Geometry (kit: Desktop Qt 5.1.1 GCC 64bit)
When executing step 'Make'
12:25:21: Elapsed time: 00:00.

Last edited on


Just discovered gcc 4.7 doesn't handle inherited constructors: guess that is the cause of most of the problems. Will look at upgrading the compiler.

I should be able to call the base class constructor from the initialiser list though.

Regards
> I should be able to call the base class constructor from the initialiser list though.
┬┐ah?

> angle MyAngle1(); //no error, but how to construct?
that's a function definition
angle MyAngle; would attempt use the default constructor. It should fail, because there is no default constructor.
Hi ne555,

I am in the middle of installing clang, and will probably upgrade from fedora 17 to fedora 20 as well.

I guess this is the easiest & best path and I am sure your code will work, once I can inherit constructors.

Having to write a constructor for each new class kind of defeats the purpose of using the template code, so I am going to can that idea :+o

Any way I will let you know how I get on.

Cheers



Al-right, it works as expected with clang++ from the command line.

Thanks very much for your help again :+D

Cheers
Topic archived. No new replies allowed.