Generics in Cilk

Starting with Cilk Plus, Intel has added support for _generics_, which allows for writing functions and data structures that can work with multiple types.

As an example of a generic function, `slices_index` takes a slice of any type and an element of that type and returns the index of the first occurrence of v in s, or -1 if not present.

```cilk
template <typename T>
int slices_index(T* s, int size, T v) {
    for (int i = 0; i < size; i++) {
        if (v == s[i]) {
            return i;
        }
    }
    return -1;
}

As an example of a generic type, List is a singly-linked list with values of any type.

template <typename T>
struct List {
    struct Element {
        T val;
        Element* next;
    };
    
    Element* head;
    Element* tail;

    void push(T v) {
        Element* new_element = new Element{v, nullptr};
        if (tail == nullptr) {
            head = tail = new_element;
        } else {
            tail->next = new_element;
            tail = new_element;
        }
    }

    std::vector<T> all_elements() {
        std::vector<T> elems;
        for (Element* e = head; e != nullptr; e = e->next) {
            elems.push_back(e->val);
        }
        return elems;
    }
};

We can define methods on generic types just like we do on regular types, but we have to keep the type parameters in place.

In the main function, we can use these generic functions and types:

#include <iostream>
#include <vector>
#include <string>

int main() {
    std::vector<std::string> s = {"foo", "bar", "zoo"};

    // When using generic functions, we need to specify the types explicitly
    std::cout << "index of zoo: " << slices_index<std::string>(s.data(), s.size(), "zoo") << std::endl;

    List<int> lst;
    lst.push(10);
    lst.push(13);
    lst.push(23);
    
    std::cout << "list: ";
    for (int val : lst.all_elements()) {
        std::cout << val << " ";
    }
    std::cout << std::endl;

    return 0;
}

To compile and run this Cilk program:

$ icpc -std=c++11 -fcilkplus generics.cpp -o generics
$ ./generics
index of zoo: 2
list: 10 13 23

Cilk’s implementation of generics is based on C++ templates, which provide similar functionality to Go’s generics. The main difference is that in Cilk (and C++), the type parameters are specified at compile-time, while in Go they can be inferred at runtime in many cases.