Arvutiteaduse instituut
  1. Kursused
  2. 2023/24 kevad
  3. Programmeerimine keeles C++ (MTAT.03.158)
EN
Logi sisse

Programmeerimine keeles C++ 2023/24 kevad

  • Home
  • Labs
    • Submission of solutions
    • Results
  • Examination times
  • Guides
  • References

Lab 3: templates, C++ Standard Library containers, iterators

General guidelines

Important! Read the guidelines on formatting from the course homepage! Tasks are submitted on the course homepage. Submissions by e-mail are not accepted. If you have any questions then write to the list or a lab instructor.

There are 14 days for solving the task.

Deadline: 24.03.2022 23:59:59

NB: As of this practice, documentation with Doxygen is no longer mandatory. Students will be expected to have good code in the future.

Task 1 – Geometry in n-dimensional space.

In this lab we write the most complete point, line and sphere classes so far. We use class templates to create geometrical objects in n-dimensional space (note: your code should give trivial answers even when initialized with 0-dimensions). To create the following classes use templates.

If you are not going to have any cpp-files, then do not create a ‘.a’ geometry-library file. In the first task that may be the ćase.

1.1 Universal point (point.h) (3 points)

Create a class Point, to which you can give the number of coordinates (template <unsigned short n>). The given non-negative integer n specifies how many dimensions the point has. Save the point's coordinates to STL container class std::list into a variable named coords.

Some examples:

Point<2> twoDimensionPoint; // point on a plane
Point<10> tenDimensionPoint; // point in 10 dimensions

Add following methods to the class:

MethodTask
Point<n> ()Initializes coordinates with 0’s
Point<n> (list<float> crds)Initializes coordinates with given values
float distanceFrom (Point<n> v)Returns the distances from another same-dimension point
string toString ()Returns point's string representation (x1, x2, ..., xn)
operator <<Outputs point's info (use toString method)

A friend keyword is helpful in overloading the output stream shift operator .

NB! Using a friend keyword inside templates can cause weird compilation errors or warnings. See also https://isocpp.org/wiki/faq/templates#template-friends.

NB! Overloading an operator is easier if the Point object specified as a parameter is not constant. See the tips on the last page to write a nicer solution.

If error conditions occur, such as if the number n of coordinates specified in the template differs from the size of the predefined coordinate vector, throw string-typed exception (see Material). Write a human-readable text as an exception text on what went wrong. Note that 0-dimension point is legal and is not an error situation.

1.2. Universal straight section (line.h) (1 point)

Create a class template Line with a class parameter T (template <class T>). A class represents a straight line over points of any dimension. The class has two attributes - p1 and p2, both are of type T - they represent the vertices of a straight line. As a result, it must be possible to create lines with two vertices as follows:

Line< Point<2> > kahem66tmelineSirgl6ik;
Line< Point<7> > seitsmem66tmelineSirgl6ik;

Add methods to the class:

MethodTask
Line <T> ()default constructor - creates a line (using <T> default constructor)
Line <T> (T np1, T np2)parameter constructor - initialized ​​class attributes
float length ()returns the length of a straight line using the class T method distanceFrom
string toString ()returns a string representation of the line ((point1)-(point2))
operator <<outputs line data (use toString method)

1.3. Universal Sphere ( sphere.h) (3 points)

Create a class template Sphere with a point class parameter T (template <class T>). The class represents spheres (and, in the special case of two-dimensios circles). The class should have a T type attribute o that represents the midpoint and a float attribute r that represents the radius. The radius should never be negative.

As a result, it must be possible to make circles and spheres as follows:

Sphere< Point<2> > ring;
Sphere< Point<3> > kera;
MethodTask
Sphere ()default constructor - creates a T type point and sets the radius to zero
Sphere <T> (T no, float nr)parameter constructor - uses the given point and radius
bool contains (T v)returns true if the point v is on or inside the sphere, otherwise false
bool contains (Line <T> l)returns true if this line is inside the sphere, otherwise false
void scale (float factor)multiplies the radius of the sphere by factor
string toString ()returns the sphere as a string ((point), radius)
operator <<outputs sphere data (use toString method)

This is not part of the task, but keep in mind that there is also an option in the language to write implementations with specific parameters. For example, you can realize the calculation of the circumference and area for a two-dimensional sphere (circle) and the volume for a three-dimensional sphere as special cases. The corresponding keyword to look into is template specialization.

NB! Do not change the suggested variable names and keep the variables public. This makes testing easier. Also create a header file geometry.h that adds the headers of the point, line, and sphere classes.

Task 2 - Universal Polygon Class (3 points)

As a result of the changes, it is necessary to create a class template Polygon with parameter class T and an integer n (template <class T, unsigned short n>). The class represents n-point polygons over given points. Add these methods to the class template:

MethodTask
Polygon <T, n> ()initializes points with zeros
Polygon <T, n> (vector <T> pts)sets ​​the coordinates of the vector to the given values
float perimeter ()gives the perimeter of the polygon (sum of the lengths of the sides)
string toString ()returns a polygon as a string ((point1),...,(pointn))
operator <<outputs polygon data (use toString method)

Hints

For overloading the output stream operator <<, first see the “Read more about uploading the output flow routing operator” material in the second lab.

If a parameter of a function is aconstant, when passing that parameter to another function it must remain a constant. For example, if the class is described as follows

class Vector2 {
  ...
  string toString();
  friend ostream& operator<<(ostream& out, const Vector2& vec);
}

Then the operator overload cannot be realized this way

ostream& operator<<(ostream& out, const Vector2& vec) {
  out << vec.toString();                      // veateade
  return out;
}

The problem is that the compiler does not know what the toString method does and whether that method changes the Vector2 parameter. The solution is to write const at the end of the method (string toString() const;), which ensures that the parameter of that method is not modified and allows you to call toString on constant variables.

Additional Task 3 - Function Objects or Lambda Functions (1 additional point)

General requirements

The third task is for you to choose between two exercises. You can solve 3.1 or 3.2 or both, but points can only be earned for one. When presenting both additional tasks, the first or function object exercise is assessed. As you complete the task, you can practice working with algorithms and function objects. The resulting code (if any) should be in a library file with the name libmyfunctors.a and header myfunctors.h. To test the solution, we use a program that runs the code you write and checks that the results meet the requirements of the task. We recommend that you do a test program where you try out your own solution. The test program is not evaluated.

Place the solution in the same directory tree as the geometry code for the first problem. By default, the makefile must build a ready-made library.

Part 3.1 - Function objects or functors

A function object with state and one parameter to sum elements in a container

A quick introduction to the topic of status functors. Functions can also be defined before they are implemented. This provides a nice additional opportunity to use them, for example, in collecting values. The functor is created before starting the algorithm, and after the work is completed, the result is read inside the object. To support that the functor must have, besides the operator (), required variables and methods must be defined. Your task is to write a class template SumElements<T> with class parameter T, which could be used to sum containers containing T type elements. We assume that type T has implemented the operator + (e.g. int, float, string). If the object is tried to be used with a type which does not have the operator implemented, an error will occur.

The function object could be implemented in a header. An example on how the object should be able to be used:

vector<unsigned long> values;            // vector of long
SumElements<unsigned long> addThisValue; // functor of same type
addThisValue = for_each(values.begin(), values.end(), addThisValue); // sum
unsigned long sum = addThisValue.result ();   // read the sum

The solution must work for both numeric types and words. Tip: Using curly parentheses when creating an object resets numeric types to zero and words to empty words. For example

int x;   // x’s value can be anything
int x{}; // x is initialized to 0
int x(); // Compiler considers this a function declaration

Part 3.2 - Aggregation of container elements using the lambda function

A lambda or lambda function is a function that can be used to create a single function object, such as for algorithms. Therefore, there is no need to define a separate function object for the algorithm, which in turn saves time and reduces code. The body of the lambda function usually consists of three parts:

[capture_clause] (arguments) {expression}

// capture_clause - Variables that may be needed in the expression, such as to store the amount. Only captured variables can be used
// arguments - Arguments given to a lambda expression (similar to a function).
// expression - An expression for the lambda function that defines behavior.

// Variables can also be captured individually by reference or value as needed.
// To capture all scope variables by reference, use [&]
// Examples of lambda functions

[& a] (int x, int y = 1) {return a - = x * y; } // We only capture 1 scope variable by reference (a).
[&] (int x) {return a - = x + b; } // We capture all scope variables (a, b) by reference.
[a] (int x, int y = 1) {return a - = x * y; } // Let's capture one scope variable (a) by value.
[ = ] (int x, int y = 1) {return a - = x * y + b; } // We capture all scope variables by (a, b).

The lambda function actually returns a function object, or functor.

Example of using the lambda function:

vector<int> arvuvektor {32,71,12,45,26,80,53}; // define the vector with numbers
// The third argument: "[] (int x) {return (x% 2 == 0);}" is a lambda function
// Local scope variables are not used, so no variables are captured.
partition (arvuektor .begin (), arvuvektor.end (), [] (int x) {return (x% 2 == 0);});
// result: 12.26, 32, 80, 45, 53, 71

The task is to write a template function that accepts vectors of type T and return their sum. Assume that elements of the type T have a defined operator + and can also be shifted to the output stream. The function should be implemented using for_eachi and the appropriate lambda function. The body of the template function is as follows:

template <typename T>
T summeeri_malli_vektor( vector<T> vec )
{
     // Implement function
}

The template function could be implemented in the header. An example of how a feature should be available.

vector<string> values {"a","b","c","d","e"};       // vector of letters / words
vector<int>    values1 {5,4,3,2,1};                // vector of ints
vector<float>  values2 {5.0f,4.0f,3.0f,2.0f,1.0f}; // vector of floats

cout << "Sum is: " << summeeri_malli_vektor(values)  << endl; // prints "Sum is abcde"
cout << "Sum is: " << summeeri_malli_vektor(values1) << endl; // prints "Sum is 15"
cout << "Sum is: " << summeeri_malli_vektor(values2) << endl; // prints "Sum is 15.000000"

Additional information:

https://en.cppreference.com/w/cpp/language/lambda

http://en.cppreference.com/w/cpp/language/value_initialization

http://en.cppreference.com/w/cpp/language/default_initialization

  • Arvutiteaduse instituut
  • Loodus- ja täppisteaduste valdkond
  • Tartu Ülikool
Tehniliste probleemide või küsimuste korral kirjuta:

Kursuse sisu ja korralduslike küsimustega pöörduge kursuse korraldajate poole.
Õppematerjalide varalised autoriõigused kuuluvad Tartu Ülikoolile. Õppematerjalide kasutamine on lubatud autoriõiguse seaduses ettenähtud teose vaba kasutamise eesmärkidel ja tingimustel. Õppematerjalide kasutamisel on kasutaja kohustatud viitama õppematerjalide autorile.
Õppematerjalide kasutamine muudel eesmärkidel on lubatud ainult Tartu Ülikooli eelneval kirjalikul nõusolekul.
Courses’i keskkonna kasutustingimused