Examples

Each example is taken from the test suite for Tolc and, given that you use the latest version, you can expect them all to work.

Each C++ library named MyLib exports as a python module called MyLib, in every test the module name is simply m for brevity. All tests use the python builtin unittest library. The examples that follow contains a bit of C++ code, and the respective python code using it. Each python example is wrapped in the following boilerplate that is removed to make the examples more readable:

import unittest
import m

class TestMyLib(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        pass

    def test_m(self):
        # The actual python example body goes here
        self.assertEqual(m.sayTen(), 10)

if __name__ == "__main__":
    unittest.main()

Classes


#include <string>
#include <string_view>

class WithConstructor {
public:
    explicit WithConstructor(std::string s) : m_s(s) {}

    static int const i = 5;

    // This class has a readwrite variable
    int readwrite = 10;

    std::string getS() { return m_s; }
    std::string_view getSView() { return m_s; }

private:
    std::string m_s;
};

class WithFunction {
public:
    int add(int i, int j) {
        return i + j;
    }
};

class WithPrivateFunction {
    double multiply(double i, double j) {
        return i * j;
    }
};

namespace MyLib {

    class Nested {
    public:
        double divideByTwo(double d) {
            return d / 2;
        }
    };
}

/** Documentation carries over */
struct Documentation {};

/*****************************
* JavaDoc Style
* is
* boxy
****************************/
struct JavaDoc {};


# You can access static variables without instantiating class
self.assertEqual(m.WithConstructor.i, 5)

# Creating classes via their constructor
with_constructor = m.WithConstructor("Hello")
self.assertEqual(with_constructor.getS(), "Hello")

# Documentation for variables carries over aswell
self.assertIn("This class has a readwrite variable", m.WithConstructor.readwrite.__doc__)

# Named arguments in constructors
with_constructor = m.WithConstructor(s="named argument")
self.assertEqual(with_constructor.getS(), "named argument")
self.assertEqual(with_constructor.getSView(), "named argument")

# Member functions are available after construction
with_function = m.WithFunction()
self.assertEqual(with_function.add(2, 5), 7)

# Private functions have no bindings
with self.assertRaises(AttributeError) as error_context:
    with_private_function = m.WithPrivateFunction()
    with_private_function.multiply(3, 2)

self.assertEqual(len(error_context.exception.args), 1)
# print(error_context.test_case)
self.assertEqual(
    "'m.WithPrivateFunction' object has no attribute 'multiply'",
    error_context.exception.args[0],
    "Not correct exception on private functions",
)

# Classes under namespaces are available under the corresponding submodule
nested = m.MyLib.Nested()
self.assertEqual(nested.divideByTwo(10), 5)

# Different styles of documentation on classes carries over
self.assertIn("Documentation carries over", m.Documentation.__doc__)
self.assertIn("JavaDoc Style", m.JavaDoc.__doc__)


Documentation Styles


// One line comment
class OneLiner {};

/** Single multi line comment */
class SingleMulti {};

/**
* Multi
* line
* comment
*/
class Multi {};

/**
Bare multi
Another line
*/
class BareMulti {};

/*!
* Qt style
*/
class QtStyle {};

/*****************************
* JavaDoc Style
* is
* boxy
****************************/
class JavaDoc {};

///
/// Triplets is a commitment
///
class Triplets {};

//!
//! This is one of the doxy styles
//!
class DoxyBang {};


# These types of documentations are supported for:
#   Classes
#   Member variables
#   Enums
#   Functions

self.assertIn("One line comment", m.OneLiner.__doc__)

self.assertIn("Single multi line", m.SingleMulti.__doc__)

self.assertIn("Multi", m.Multi.__doc__)

self.assertIn("Bare multi", m.BareMulti.__doc__)

self.assertIn("Qt style", m.QtStyle.__doc__)

self.assertIn("JavaDoc Style", m.JavaDoc.__doc__)

self.assertIn("Triplets", m.Triplets.__doc__)

self.assertIn("one of the doxy styles", m.DoxyBang.__doc__)

Enums


enum Unscoped {
    Under,
    Uboat,
};

enum class Scoped {
    Sacred,
    Snail,
};

class EnumTest {
public:
    explicit EnumTest(Scoped _s) : s(_s) {};

    Scoped s;
};

Unscoped f(Unscoped u) {
    return u;
}

namespace NS {
    // Documentation describing the enum
    enum class Deep {
        Double,
        Down,
    };
}



# C++11 enums work
scoped = m.Scoped.Snail
enumTest = m.EnumTest(scoped)
self.assertEqual(enumTest.s, scoped)

# Aswell as legacy enums
unscoped = m.Unscoped.Uboat
u = m.f(unscoped)
self.assertEqual(u, unscoped)

# Enums under namespaces are available under the corresponding submodule
deep = m.NS.Deep.Down
self.assertNotEqual(deep, m.NS.Deep.Double)

# Documentation carries over from C++
self.assertIn("Documentation describing the enum", m.NS.Deep.__doc__)

Functions


#include <fstream>
#include <string>

void sayHello() {
    std::ofstream f("hello.txt");
    f << "Hello!";
    f.close();
}

void addYourOwn(std::string content) {
    std::ofstream f("hello.txt");
    f << content;
    f.close();
}

/**
* Documentation carries over
*/
int calculate() {
    return 5;
}

// Different documentation styles are supported
int missingArgumentsNaming(int, int i) {
    return i;
}

char firstLetter(std::string_view s) {
    return s[0];
}

int static getZero() {
    return 0;
}


m.sayHello()
with open("hello.txt", "r") as f:
    self.assertEqual(f.readline(), "Hello!")

content = "This is from python!"
m.addYourOwn(content)
with open("hello.txt", "r") as f:
    self.assertEqual(f.readline(), content)

result = m.calculate()
self.assertEqual(result, 5)
self.assertIn("Documentation carries over", m.calculate.__doc__)

# Without naming variables is fine
result = m.missingArgumentsNaming(2, 5)
self.assertEqual(result, 5)
self.assertIn("Different documentation styles are supported", \
  m.missingArgumentsNaming.__doc__)

# Not possible to name any variables unless they are all known
with self.assertRaises(TypeError) as error_context:
  result = m.missingArgumentsNaming(2, i=5)

# std::string_view works fine
result = m.firstLetter("Hello")
self.assertEqual(result, "H")

# Static functions are just normal module functions in python
self.assertEqual(m.getZero(), 0)

Global Variables


#include <string>

static int i = 0;
namespace Nested {
    int i = 0;
    std::string s = "Hello world";
}


# Starts at 0 and can be changed
self.assertEqual(m.i, 0)
m.i = 5
self.assertEqual(m.i, 5)

# Nested with the same name
self.assertEqual(m.Nested.i, 0)

# More complex variables are available aswell
self.assertEqual(m.Nested.s, "Hello world")

Inheritence


#include <string>

struct Pet {
    Pet(const std::string &name) : name(name) { }
    std::string name;
};

struct Dog : public Pet {
    Dog(const std::string &name) : Pet(name) { }
    std::string bark() const { return "woof!"; }
};


fido = m.Dog("Fido")

# Inherits public properties
self.assertEqual(fido.name, "Fido")

# But has its new functions
self.assertEqual(fido.bark(), "woof!")

Member Variables


#include <string>

class SimpleMember {
public:
    explicit SimpleMember() : myString("Hello") {}

    std::string myString;
};

class ConstMember {
public:
    const int i = 42;
};

class PrivateMember {
public:
    explicit PrivateMember(std::string s) : myString(s) {}

private:
    std::string myString;
};

namespace MyLib {

    class Nested {
    public:
        double d = 4.3;
    };
}



# Mutable member variables can be changed
simpleMember = m.SimpleMember()
self.assertEqual(simpleMember.myString, "Hello")
simpleMember.myString = "Changed now!"
self.assertEqual(simpleMember.myString, "Changed now!")

constMember = m.ConstMember()
self.assertEqual(constMember.i, 42)

# Const member variables cannot be changed
with self.assertRaises(AttributeError) as error_context:
    constMember.i = 0

self.assertEqual(len(error_context.exception.args), 1)
self.assertEqual(
    "can't set attribute",
    error_context.exception.args[0],
    "Prohibiting changing const variables does not work!",
)

# Private member variables are not available
with self.assertRaises(AttributeError) as error_context:
    privateMember = m.PrivateMember("Hello")
    print(privateMember.myString)

self.assertEqual(len(error_context.exception.args), 1)
self.assertEqual(
    "'m.PrivateMember' object has no attribute 'myString'",
    error_context.exception.args[0],
    "Prohibiting changing const variables does not work!",
)

nested = m.MyLib.Nested()
self.assertEqual(nested.d, 4.3)

Namespaces


#include <string>

/*
* MyLib contains a bunch of MyLib functions
*/
namespace MyLib {

int complexFunction() {
    return 5;
}

    namespace We {
        namespace Are {
            namespace Going {
                namespace Pretty {
                    namespace Deep {
                        std::string meaningOfLife() {
                            return "42";
                        }
                    }
                }
            }
        }
    }
}



# Namespaces corresponds to submodules
result = m.MyLib.complexFunction()
self.assertEqual(result, 5)

# Documentation carries over for namespaces
self.assertIn("MyLib contains a bunch of MyLib functions", \
  m.MyLib.__doc__)

# You can nest namespaces arbitrarily deep
lifeProTips = m.MyLib.We.Are.Going.Pretty.Deep.meaningOfLife()
self.assertEqual(lifeProTips, "42")

Operators


#include <string>

class MyClass {
public:
  explicit MyClass(int v) : value(v) {}

  // +-*/&
  MyClass operator+(int i) { return MyClass(value + i); }
  MyClass operator-(int i) { return MyClass(value - i); }
  MyClass operator*(int i) { return MyClass(value * i); }
  MyClass operator/(int i) { return MyClass(value / i); }
  MyClass operator%(int i) { return MyClass(value % i); }

  // Assignment
  MyClass& operator+=(const MyClass& rhs) { value += rhs.value; return *this; }
  MyClass& operator-=(const MyClass& rhs) { value -= rhs.value; return *this; }
  MyClass& operator*=(const MyClass& rhs) { value *= rhs.value; return *this; }
  MyClass& operator/=(const MyClass& rhs) { value /= rhs.value; return *this; }
  MyClass& operator%=(const MyClass& rhs) { value %= rhs.value; return *this; }

  // Comparisons
  bool operator==(const MyClass &rhs) { return value == rhs.value; }
  bool operator!=(const MyClass &rhs) { return value != rhs.value; }
  bool operator<(const MyClass &rhs) { return value < rhs.value; }
  bool operator>(const MyClass &rhs) { return value > rhs.value; }
  bool operator<=(const MyClass &rhs) { return value <= rhs.value; }
  bool operator>=(const MyClass &rhs) { return value >= rhs.value; }

  // Subscript
  MyClass operator[](unsigned idx) { return MyClass(static_cast<int>(idx)); }

  // Call
  int operator()(int x) { return value + x; }
  std::string operator()(std::string const& x) { return x + std::to_string(value); }

  int value;
};


my_class = m.MyClass(10)
self.assertEqual(my_class.value, 10)

# Normal operators translate as expected
self.assertEqual((my_class + 5).value, 15)
self.assertEqual((my_class - 5).value, 5)
self.assertEqual((my_class * 5).value, 50)
self.assertEqual((my_class / 5).value, 2)
self.assertEqual((my_class % 3).value, 1)

other = m.MyClass(5)
# Comparison operators
self.assertTrue(my_class != other)
self.assertTrue(my_class > other)
self.assertTrue(my_class >= other)

self.assertFalse(my_class == other)
self.assertFalse(my_class < other)
self.assertFalse(my_class <= other)

# Can also use the {operator}= functions
# other.value = 5
my_class += other
self.assertEqual(my_class.value, 15)
my_class -= other
self.assertEqual(my_class.value, 10)
my_class *= other
self.assertEqual(my_class.value, 50)
my_class /= other
self.assertEqual(my_class.value, 10)
my_class %= other
self.assertEqual(my_class.value, 0)

# Subscript []
self.assertEqual(my_class[100].value, 100)

# Call ()
self.assertEqual(my_class(100), 100)
# Overloading works
self.assertEqual(my_class("The inner value is: "), "The inner value is: 0")

Overloaded Functions


#include <string>

// Overloaded free functions
std::string sayHello() {
    return "Hello!";
}
std::string sayHello(std::string to) {
    return std::string("Hello ") + to;
}

std::string safety() { return "Safe!"; }

class Overload {
public:
    // Overloaded constructor
    Overload() {};
    Overload(std::string) {};

    // Overloaded class functions
    std::string getStuff() { return "Stuff"; }
    std::string getStuff(std::string customStuff) { return customStuff; }

    std::string safety() { return "Safe!"; }
};



# Overloaded functions work the same as in C++
# Free function overload
self.assertEqual(m.sayHello(), "Hello!")
self.assertEqual(m.sayHello("to me!"), "Hello to me!")

# Class function overload
overload = m.Overload()
overload = m.Overload("Overloaded!")
self.assertEqual(overload.getStuff(), "Stuff")
self.assertEqual(overload.getStuff("My stuff"), "My stuff")

self.assertEqual(overload.safety(), "Safe!")
self.assertEqual(overload.safety(), m.safety())

Overriding virtual functions in python


#include <string>

class Animal {
public:
    virtual ~Animal() { }
    virtual std::string sound(int n_times, bool grumpy) = 0;
};

class Dog : public Animal {
public:
    std::string sound(int n_times, bool grumpy) override {
        if (grumpy) {
            return "No.";
        }

        std::string result;
        for (int i = 0; i < n_times; ++i) {
            result += "woof! ";
        }
        return result;
    }
};

std::string call_sound(Animal *animal) {
    return animal->sound(3, false);
}


fido = m.Dog()
grumpy = True

# Overloaded function in C++
self.assertEqual(fido.sound(1, not grumpy), "woof! ")

# Polymorphic function in C++
self.assertEqual(m.call_sound(fido), "woof! woof! woof! ")

# Inherit from virtual C++ classes in python
class Cat(m.Animal):
  # Override C++ function
  def sound(self, n_times, grumpy):
    return "No." if grumpy else "meow! " * n_times

whiskers = Cat()

# Overloaded C++ function in python
self.assertEqual(whiskers.sound(1, grumpy), "No.")
self.assertEqual(whiskers.sound(1, not grumpy), "meow! ")

# Polymorphic function in C++ called with python object
self.assertEqual(m.call_sound(whiskers), "meow! meow! meow! ")

Overriding virtual in python


#include <string>

class Animal {
public:
    virtual ~Animal() { }
    virtual std::string sound(int n_times, bool grumpy) = 0;
};

class Dog : public Animal {
public:
    std::string sound(int n_times, bool grumpy) override {
        if (grumpy) {
            return "No.";
        }

        std::string result;
        for (int i = 0; i < n_times; ++i) {
            result += "woof! ";
        }
        return result;
    }
};

std::string call_sound(Animal *animal) {
    return animal->sound(3, false);
}


fido = m.Dog()
grumpy = True

# Overloaded function in C++
self.assertEqual(fido.sound(1, grumpy), "No.")
self.assertEqual(fido.sound(1, not grumpy), "woof! ")

# Polymorphic function in C++
self.assertEqual(m.call_sound(fido), "woof! woof! woof! ")

# Inherit from virtual C++ classes in python
class Cat(m.Animal):
  # Override C++ function
  def sound(self, n_times, grumpy):
    return "No." if grumpy else "meow! " * n_times

whiskers = Cat()

# Overloaded C++ function in python
self.assertEqual(whiskers.sound(1, grumpy), "No.")
self.assertEqual(whiskers.sound(1, not grumpy), "meow! ")

# Polymorphic function in C++ called with python object
self.assertEqual(m.call_sound(whiskers), "meow! meow! meow! ")

Simple inheritence


#include <string>

struct Pet {
    Pet(const std::string &name) : name(name) { }
    std::string name;
};

struct Dog : public Pet {
    Dog(const std::string &name) : Pet(name) { }
    std::string bark() const { return "woof!"; }
};


fido = m.Dog("Fido")

# Inherits public properties
self.assertEqual(fido.name, "Fido")

# But has its new functions
self.assertEqual(fido.bark(), "woof!")

Smart Pointers


#include <memory>

struct Example {
    int m_hi = 5;
};

struct ExampleShared {
    int m_hi = 10;
};

std::unique_ptr<Example> create_unique() {
    return std::make_unique<Example>();
}

std::shared_ptr<ExampleShared> create_shared() {
    return std::make_shared<ExampleShared>();
}


# std::unique_ptr acts as a normal value
# Note that passing a std::unique_ptr as an argument gives an error
#   See https://pybind11.readthedocs.io/en/stable/advanced/smart_ptrs.html
u = m.create_unique()
self.assertEqual(u.m_hi, 5)

# std::shared_ptr acts as a normal value
s = m.create_shared()
self.assertEqual(s.m_hi, 10)

std::array


#include <array>
#include <string>

class WithMember {
public:
    explicit WithMember(std::array<std::string, 2> s) : m_s(s) {}

    std::array<std::string, 2> getS() { return m_s; }

private:
    std::array<std::string, 2> m_s;
};

class WithFunction {
public:
    int sum(std::array<int, 5> v) {
        int s = 0;
        for (auto i : v) {
            s += i;
        }
        return s;
    }
};



# std::array translates to a normal array in python
my_array = ["hi", "ho"]
with_member = m.WithMember(my_array)
self.assertEqual(with_member.getS(), my_array)

with_function = m.WithFunction()
self.assertEqual(with_function.sum([1, 2, 3, 4, 5]), 15)

# It still corresponds to a fixed amount of elements
for incompatible_array in [["too many", "too many", "too many"], ["too few"]]:
    with self.assertRaises(TypeError) as error_context:
        with_member = m.WithMember(incompatible_array)

    self.assertEqual(len(error_context.exception.args), 1)
    self.assertTrue(
        "incompatible constructor arguments" in error_context.exception.args[0],
        "Error msg does not mention incompatible arguments: "
        + str(error_context.exception.args[0]),
    )
    self.assertTrue(
        "Invoked with: " + str(incompatible_array)
        in error_context.exception.args[0],
        "Error msg does not mention the given arguments: " + str(error_context.exception.args[0]),
    )

std::complex


#include <complex>

using namespace std::complex_literals;

std::complex<int> i() {
    return 5;
}

std::complex<double> d() {
    return 1. + 2i;
}

std::complex<float> f() {
    return 0.f + 5if;
}

std::complex<double> r(std::complex<double> d) {
    return d;
}


# std::complex translates to a complex in python
i = m.i()
self.assertEqual(i.real, 5)
self.assertEqual(i.imag, 0)

d = m.d()
self.assertEqual(d.real, 1)
self.assertEqual(d.imag, 2)

f = m.f()
self.assertEqual(f.real, 0)
self.assertEqual(f.imag, 5)

# Using python builtin complex class
r = m.r(complex(1, 2))
self.assertEqual(r.real, 1)
self.assertEqual(r.imag, 2)

std::deque


#include <string>
#include <deque>

class WithMember {
public:
    explicit WithMember(std::deque<std::string> s) : m_s(s) {}

    std::deque<std::string> getS() { return m_s; }

private:
    std::deque<std::string> m_s;
};

class WithFunction {
public:
    int sum(std::deque<int> v) {
        int s = 0;
        for (auto i : v) {
            s += i;
        }
        return s;
    }
};



# std::deque translates to a normal array in python
my_array = ["hi", "ho"]
with_member = m.WithMember(my_array)
self.assertEqual(with_member.getS(), my_array)

with_function = m.WithFunction()
self.assertEqual(with_function.sum([1, 2, 3]), 6)

std::filesystem::path


#include <filesystem>
#include <vector>

std::filesystem::path takingPath(std::filesystem::path p) {
    return p;
}

std::string toString(std::filesystem::path p) {
    return p.string();
}

std::filesystem::path joinPaths(std::vector<std::filesystem::path> arrayToSum) {
    std::filesystem::path sum;
    for (auto f : arrayToSum) {
        sum /= f;
    }
    return sum;
}


# std::filesystem::path translates to pathlib.Path in python
from pathlib import Path

p0 = Path("Hello")
result0 = m.takingPath(p0)
self.assertEqual(result0, p0)

p1 = Path("Something")
toString = m.toString(p1)
self.assertEqual(toString, p1.name)

result1 = m.joinPaths([p0, p1])
self.assertEqual(result1, p0 / p1)

std::function


#include <functional>
#include <vector>

double takingFunction(std::function<double(int)> callMe) {
    return callMe(5);
}

std::function<int(int)> returnFunction(const std::function<int(int)> &f) {
    return [f](int i) {
        return f(i) + 1;
    };
}

int accumulateArrayOfFunctions(std::vector<std::function<int()>> arrayToSum) {
    int sum = 0;
    for (auto f : arrayToSum) {
        sum += f();
    }
    return sum;
}


def callback(i):
  return i

# You can send a python function as a C++ callback
result0 = m.takingFunction(callback)
self.assertEqual(result0, 5.0)

# Or in the other direction
inc_by_one = m.returnFunction(callback)
self.assertEqual(inc_by_one(5), 6)

def fiver():
  return 5

# Or a vector of functions
result1 = m.accumulateArrayOfFunctions([fiver, fiver])
self.assertEqual(result1, 10)

std::list


#include <string>
#include <list>

class WithMember {
public:
    explicit WithMember(std::list<std::string> s) : m_s(s) {}

    std::list<std::string> getS() { return m_s; }

private:
    std::list<std::string> m_s;
};

class WithFunction {
public:
    int sum(std::list<int> v) {
        int s = 0;
        for (auto i : v) {
            s += i;
        }
        return s;
    }
};



# std::list translates to a normal array in python
my_array = ["hi", "ho"]
with_member = m.WithMember(my_array)
self.assertEqual(with_member.getS(), my_array)

with_function = m.WithFunction()
self.assertEqual(with_function.sum([1, 2, 3]), 6)

std::map


#include <map>
#include <string>

class MyClass {
public:
    explicit MyClass(std::map<std::string, int> s) : m_s(s) {}

    std::map<std::string, int> getS() { return m_s; }

    std::string getValue(std::map<int, std::string> const& m, int key) {
        auto it = m.find(key);
        if (it != m.end()) {
            return it->second;
        }
        return "";
    }

private:
    std::map<std::string, int> m_s;
};



# std::map translates to a normal dictionary in python
my_map = {"hi": 4, "ho": 5}
c = m.MyClass(my_map)
self.assertEqual(c.getS(), my_map)

# The maps are typed on the C++ side
for incopatible_map in [{"key": "value"}, {5: 2}]:
    with self.assertRaises(TypeError) as error_context:
        c = m.MyClass(incopatible_map)
        c.getValue(incopatible_map, 5)

    self.assertEqual(len(error_context.exception.args), 1)
    self.assertTrue(
        "incompatible function arguments" in error_context.exception.args[0]
        or "incompatible constructor arguments"
        in error_context.exception.args[0],
        "Error msg does not mention incompatible arguments: \n\t"
        + str(error_context.exception.args[0]),
    )
    self.assertTrue(
        str(incopatible_map) in error_context.exception.args[0],
        "Error msg does not mention the given arguments: \n\t"
        + str(error_context.exception.args[0]),
    )

std::optional


#include <optional>
#include <string>

class WithMember {
public:
    explicit WithMember(std::optional<std::string> s) : m_s(s) {}

    std::optional<std::string> getS() { return m_s; }

private:
    std::optional<std::string> m_s;
};

class WithFunction {
public:
    std::optional<int> getNullopt() {
        return std::nullopt;
    }
};



# std::optional is either the value or None in python
greeting = "hello"
with_member = m.WithMember(greeting)
self.assertEqual(with_member.getS(), greeting)

with_function = m.WithFunction()
self.assertEqual(with_function.getNullopt(), None)

std::pair


#include <string>

class MyClass {
public:
    explicit MyClass(std::pair<std::string, int> s) : m_s(s) {}

    std::pair<std::string, int> getS() { return m_s; }

private:
    std::pair<std::string, int> m_s;
};

class WithFunction {
public:
    int sum(std::pair<int, int> v) {
        return v.first + v.second;
    }
};



# Converts to a tuple, but is convertible from array aswell
my_array = ["hi", 4]
for t in [my_array, tuple(my_array)]:
    with_member = m.MyClass(t)
    self.assertEqual(with_member.getS(), tuple(t))

with_function = m.WithFunction()
self.assertEqual(with_function.sum((1, 2)), 3)

std::set


#include <set>
#include <string>

class MyClass {
public:
    explicit MyClass(std::set<std::string> s) : m_s(s) {}

    std::set<std::string> getS() { return m_s; }

    int getValue(std::set<int> const& m, int key) {
        auto it = m.find(key);
        if (it != m.end()) {
            return *it;
        }
        return -1;
    }

private:
    std::set<std::string> m_s;
};



# std::set translates to a normal array or a set in python
mySet = {"hi", "this is a set"}
c = m.MyClass(mySet)
self.assertEqual(c.getS(), mySet)

self.assertEqual(c.getValue({1, 2, 3}, 3), 3)
self.assertEqual(c.getValue({1, 2, 3}, 4), -1)

# Test set of the wrong type
for incompatibleset in [{"key": "value"}, (5, 2)]:
    with self.assertRaises(TypeError) as error_context:
        c = m.MyClass(incompatibleset)
        c.getValue(incompatibleset, 5)

self.assertEqual(len(error_context.exception.args), 1)
self.assertTrue(
    "incompatible function arguments" in error_context.exception.args[0]
    or "incompatible constructor arguments" in error_context.exception.args[0],
    "Error msg does not mention incompatible arguments: \n\t"
    + str(error_context.exception.args[0]),
)
self.assertTrue(
    str(incompatibleset) in error_context.exception.args[0],
    "Error msg does not mention the given arguments: \n\t"
    + str(error_context.exception.args[0]),
)



std::tuple


#include <string>
#include <tuple>

class MyClass {
public:
    explicit MyClass(std::tuple<std::string, int> s) : m_s(s) {}

    std::tuple<std::string, int> getS() { return m_s; }

    std::tuple<std::string, int> m_s;
};

class WithFunction {
public:
    double sum(std::tuple<int, int, float, double> t) {
        return std::get<0>(t)
               + std::get<1>(t)
               + std::get<2>(t)
               + std::get<3>(t);
    }
};



# Converts to a tuple, but is convertible from array aswell
my_array = ["hi", 4]
for t in [my_array, tuple(my_array)]:
    with_member = m.MyClass(t)
    self.assertEqual(with_member.getS(), tuple(t))

with_function = m.WithFunction()
self.assertAlmostEqual(with_function.sum((1, 2, 3.3, 2.0)), 8.3, delta=0.0001)

std::unordered_map


#include <string>
#include <unordered_map>

class MyClass {
public:
    explicit MyClass(std::unordered_map<std::string, int> s) : m_s(s) {}

    std::unordered_map<std::string, int> getS() { return m_s; }

    std::string getValue(std::unordered_map<int, std::string> const& m, int key) {
        auto it = m.find(key);
        if (it != m.end()) {
            return it->second;
        }
        return "";
    }

private:
    std::unordered_map<std::string, int> m_s;
};



# std::unordered_map translates to a normal dictionary in python
myunordered_map = {"hi": 4, "ho": 5}
c = m.MyClass(myunordered_map)
self.assertEqual(c.getS(), myunordered_map)

# Test unordered_map of the wrong type
for incompatible_map in [{"key": "value"}, {5: 2}]:
    with self.assertRaises(TypeError) as error_context:
        c = m.MyClass(incompatible_map)
        c.getValue(incompatible_map, 5)

    self.assertEqual(len(error_context.exception.args), 1)
    self.assertTrue(
        "incompatible function arguments" in error_context.exception.args[0]
        or "incompatible constructor arguments"
        in error_context.exception.args[0],
        "Error msg does not mention incompatible arguments: \n\t"
        + str(error_context.exception.args[0]),
    )
    self.assertTrue(
        str(incompatible_map) in error_context.exception.args[0],
        "Error msg does not mention the given arguments: \n\t"
        + str(error_context.exception.args[0]),
    )


std::unordered_set


#include <string>
#include <unordered_set>

class MyClass {
public:
    explicit MyClass(std::unordered_set<std::string> s) : m_s(s) {}

    std::unordered_set<std::string> getS() { return m_s; }

    int getValue(std::unordered_set<int> const& m, int key) {
        auto it = m.find(key);
        if (it != m.end()) {
            return *it;
        }
        return -1;
    }

private:
    std::unordered_set<std::string> m_s;
};



# std::unordered_set translates to a normal array or a set in python
my_unordered_set = {"hi", "this is a unordered_set"}
c = m.MyClass(my_unordered_set)
self.assertEqual(c.getS(), my_unordered_set)

self.assertEqual(c.getValue({1, 2, 3}, 3), 3)
self.assertEqual(c.getValue({1, 2, 3}, 4), -1)

# Test unordered_set of the wrong type
for incompatible_set in [{"key": "value"}, (5, 2)]:
    with self.assertRaises(TypeError) as error_context:
        c = m.MyClass(incompatible_set)
        c.getValue(incompatible_set, 5)

self.assertEqual(len(error_context.exception.args), 1)
self.assertTrue(
    "incompatible function arguments" in error_context.exception.args[0]
    or "incompatible constructor arguments" in error_context.exception.args[0],
    "Error msg does not mention incompatible arguments: \n\t"
    + str(error_context.exception.args[0]),
)
self.assertTrue(
    str(incompatible_set) in error_context.exception.args[0],
    "Error msg does not mention the given arguments: \n\t"
    + str(error_context.exception.args[0]),
)

std::valarray


#include <valarray>

std::valarray<int> get() {
    return {1, 2, 3};
}


v = m.get()
self.assertEqual(v, [1, 2, 3])

std::variant


#include <string>
#include <variant>

class WithMember {
public:
    explicit WithMember(std::variant<int, bool> s) : m_s(s) {}

    std::variant<int, bool> getS() { return m_s; }

private:
    std::variant<int, bool> m_s;
};

class WithFunction {
public:
    std::variant<int, std::string, bool> getFive() {
        return 5;
    }

    std::variant<int, std::string, bool> getHello() {
        return std::string("Hello");
    }

    std::variant<int, std::string, bool> getTrue() {
        return true;
    }
};



# std::variant translates to one of the values in python
number = 6
withNumber = m.WithMember(number)
self.assertEqual(withNumber.getS(), number)

withBool = m.WithMember(True)
self.assertEqual(withBool.getS(), True)

with_function = m.WithFunction()
self.assertEqual(with_function.getFive(), 5)
self.assertEqual(with_function.getHello(), "Hello")
self.assertEqual(with_function.getTrue(), True)

std::vector


#include <string>
#include <vector>

class WithMember {
public:
    explicit WithMember(std::vector<std::string> s) : m_s(s) {}

    std::vector<std::string> getS() { return m_s; }

private:
    std::vector<std::string> m_s;
};

class WithFunction {
public:
    int sum(std::vector<int> v) {
        int s = 0;
        for (auto i : v) {
            s += i;
        }
        return s;
    }
};



# std::vector translates to a normal array in python
my_array = ["hi", "ho"]
with_member = m.WithMember(my_array)
self.assertEqual(with_member.getS(), my_array)

with_function = m.WithFunction()
self.assertEqual(with_function.sum([1, 2, 3]), 6)

Templates


#include <array>
#include <map>
#include <string>
#include <vector>

template <typename T>
T getSomething(T something) {
  return something;
}

template std::string getSomething(std::string something);
template int getSomething(int);
template std::vector<std::string> getSomething(std::vector<std::string>);

template <typename T>
class MyClass {
public:
T myFun(T type) {
    return type;
}
};

template class MyClass<int>;
template class MyClass<std::map<char, std::vector<int>>>;
template class MyClass<std::array<int, 3>>;


# getSomething<std::string>
hi = m.getSomething("hi")
self.assertEqual(hi, "hi")

# getSomething<int>
five = m.getSomething(5)
self.assertEqual(five, 5)

# getSomething<std::vector<std::string>>
l = m.getSomething(["hi"])
self.assertEqual(l, ["hi"])

# MyClass<int>
my_class_int = m.MyClass_int()
self.assertEqual(my_class_int.myFun(25), 25)

# MyClass<std::map<char, std::vector<int>>>
my_class_map = m.MyClass_map_char_vector_int()
self.assertEqual(my_class_map.myFun({'h': [1]}), {'h': [1]})

# MyClass<std::array<int, 3>>
my_class_array = m.MyClass_array_int_3()
self.assertEqual(my_class_array.myFun([1, 2, 3]), [1, 2, 3])