CS 3130 Fall 2025
Study MaterialsMain/ReadingsOffice HoursPoliciesHWs+LabsQuizzesSubmissionSchedule
This website may change (perhaps significantly) before the semester starts.
  • 1 Caveat
  • 2 Review
  • 3 A Mathematical Vector type
  • 4 Guides
  • 5 C++ Iterators

We showed you some basic C++ last semester, including using templates like Java uses generics. But that is far from all C++ templates can do… This lab will help you explore this topic in more detail.

We recommend that you work in pairs for this lab, like those before it.

1 Caveat

There exists a subset of programmers who believe that C++ templates beyond type generics are an abomination and should never be used. I hope this lab will help you make your own opinion, but be aware that if you work for a company that uses C++ and suggest some of these techniques, you might get some blow-back…

2 Review

Begin by reviewing the C++ lab from CSO1.

We’ll be picking up from where those left off in this lab.

3 A Mathematical Vector type

In mathematics, a vector has fixed length and adding vectors of different length is meaningless. In this lab you’ll use C++ templates to make a mathematical vector class that uses the type checker to ensure at compile time that no wrong-sized operations occur.

Implement a templated mathematical vector type in C++. When you are done, the following code should do as the comments suggest (you’ll need to comment out the does not compile lines to get the others to work):

typedef vec<double, 2> vd2;
typedef vec<double, 3> vd3;
typedef vec<int,4> vi4;

int main() {
    vd3 a;
    std::cout << a << std::endl; // prints (0, 0, 0)
    
    a[2] = 2.5;
    std::cout << a << std::endl; // prints (0, 0, 2.5)

    std::cout << (a + a) << std::endl; // prints (0, 0, 5)
    std::cout << a << std::endl; // prints (0, 0, 2.5)

    vd2 b;
    std::cout << b << std::endl; // prints (0, 0)
    vi4 c;
    std::cout << c << std::endl; // prints (0, 0, 0, 0)
    
    std::cout << (a + b) << std::endl; // does not compile
    std::cout << (a + c) << std::endl; // does not compile
    
    
    c[2] = 2.5; // implicitly casts a double to an int...
    b[1] = 2.5;
    c[2] = 2;

    std::cout << b << std::endl; // prints (0, 2.5)
    std::cout << c << std::endl; // prints (0, 0, 2, 0)
    vd3 x = {1.5, 2.5, 3.5};
    std::cout << x << std::endl; // prints (1.5, 2.5, 3.5)

    vd3 y = {1, 2, 3};
    std::cout << y << std::endl; // prints (1, 2, 3)
}

You code should not contain any heap-allocated memory (no new or malloc)

When you’re done submit your C++ files to the submission site, OR show your TA what you’ve done for check-off.

4 Guides

  • Precede your struct (or class) with template <typename N, int n> so it will work with multiple types and lengths. (The only difference between struct and class in C++ is whether it defaults to public or private.)

    Note that template classes and functions cannot be defined in separate .o files. So, when template implementations are split across multiple files, usually the implementations are placed in header files.

  • Use a static array N data[n] (or the like) as the only field so avoid heap memory allocations

  • Constructors have no return type and the same name as the struct

    • your default constructor should sets the data to all 0s
    • the other should accept an initializer list, which is what the {1,2,3} turns into at compile time
      • #include <initializer_list>
      • 1 argument, a std::initializer_list<R> where R is the type of value you expect to be passed in.
      • a std::initializer_list<R> is a collection, meaning you access it by iterator
      • you’ll need to verify that the initializer list has the right number of values (it’s size() method should help)
      • we recommend using a template to pick the initializer list contained type, e.g. with template<typename R> before the function
  • Operator overloading uses special function names

    • operator + should accept only vectors of the same length
    • operator [] needs two variants
      • N& operator[] (int idx) – allows setting by index by returning a reference
      • N operator[] (int idx) const – allows reading when no reference exists
    • Printing needs a special friend notation to let you access between the ostream and vec classes:
      • a declaration like friend std::ostream& operator << (std::ostream& out, const vec<N,n>& x) placed in the class definition, indicating that the operator<< defined outside the class can access private member variables and function in the class
      • this function should use out << thing and then return out
  • It is best practice (but not technically required) to

    • put template declarations on the line before the struct or function they modify

      template <typename R>
      R dostuff(const R& t) { /*...*/ }
    • use const for all arguments you will not modify

      double sqrt(const double x)

    • use reference types const mytype& for struct arguments you don’t want to copy

      double length(const vec<double,3>& x)

    • use const for any method that does not modify this’s fields

      double length() const

5 C++ Iterators

Many STL structures in C++ use the iterator pattern to allow access. This has a somewhat different look than it does in Java or the like.

The collection offers two functions of note:

  • .begin() returns an iterator pointing to the first element of the collection
  • .end() returns an iterator pointing to the past the end element of the collection

The iterator overloads three operators of note:

  • operator != tells if two iterators point to distinct entries in the collection
  • operator * gets the item pointed to out of the iterator
  • operator ++ moves the item to the next spot in the collection

Thus, a loop that prints all items in a collection might look like

for(auto it = mycollection.begin(); // create an iterator
    it != mycollection.end();       // and while it's not off the end
    ++it) {                         // move it forward
    std::cout << *it << std::endl;  // derreference to print
}

Note in the above that when you combine a declaration and initialization, you can declare the type to be auto meaning use whatever type the initialization gives me.

CS 3130 Fall 2025

  • Charles Reiss and Kevin Skadron
  • creiss@virginia.edu
By Luther Tychnoviech and Charles Reiss. Released under the Creative Commons License CC-BY-NC-SA 4.0.