CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pybind11

Seamless operability between C++11 and Python for creating Python bindings of existing C++ code

Pending
Overview
Eval results
Files

stl-integration.mddocs/

STL Integration

pybind11 provides seamless integration with C++ Standard Template Library (STL) containers, offering both automatic conversion and explicit container binding utilities. This enables efficient data exchange between C++ containers and Python collections.

Capabilities

Automatic STL Conversions

Include <pybind11/stl.h> for automatic conversion between STL containers and Python collections.

// Automatic conversions (enabled by including pybind11/stl.h)
// std::vector<T> <-> Python list
// std::array<T, N> <-> Python list  
// std::list<T> <-> Python list
// std::deque<T> <-> Python list
// std::set<T> <-> Python set
// std::unordered_set<T> <-> Python set
// std::map<K, V> <-> Python dict
// std::unordered_map<K, V> <-> Python dict
// std::pair<T1, T2> <-> Python tuple
// std::tuple<Ts...> <-> Python tuple

Explicit Container Binding

Bind STL containers as Python classes for more control and performance.

// Vector binding
template<typename Vector, typename... Options>
class_<Vector> bind_vector(module_ &m, const char *name, const Options&... options);

// Map binding  
template<typename Map, typename... Options>
class_<Map> bind_map(module_ &m, const char *name, const Options&... options);

Container Method Binding

When using explicit binding, containers get Python-like methods.

// Vector methods (when using bind_vector)
class BoundVector {
public:
    // Python list-like interface
    void append(const T& value);
    void clear();
    void extend(const BoundVector& other);
    void insert(size_t index, const T& value);
    T pop();
    T pop(size_t index);
    void remove(const T& value);
    
    // Python indexing and slicing
    T& operator[](size_t index);
    BoundVector operator[](slice s);
    
    // Python methods
    size_t count(const T& value) const;
    size_t index(const T& value) const;
    void reverse();
    void sort();
    
    // Standard container methods  
    size_t size() const;
    bool empty() const;
    iterator begin();
    iterator end();
};

// Map methods (when using bind_map)
class BoundMap {
public:
    // Python dict-like interface
    void clear();
    bool contains(const K& key) const;
    V get(const K& key) const;
    V get(const K& key, const V& default_value) const;
    list items() const;
    list keys() const;
    V pop(const K& key);
    V pop(const K& key, const V& default_value);
    void popitem();
    void setdefault(const K& key, const V& default_value);
    void update(const BoundMap& other);
    list values() const;
    
    // Python indexing
    V& operator[](const K& key);
    
    // Standard container methods
    size_t size() const;
    bool empty() const;
    iterator begin();
    iterator end();
};

Smart Pointer Integration

STL containers work seamlessly with smart pointers.

// Automatic conversion support for smart pointers in containers
// std::vector<std::shared_ptr<T>> <-> Python list
// std::vector<std::unique_ptr<T>> <-> Python list (with move semantics)
// std::map<K, std::shared_ptr<V>> <-> Python dict

Iterator Support

Access to STL iterators from Python when using explicit binding.

// Iterator binding (automatically included with container binding)
template<typename Iterator>
class iterator_wrapper {
public:
    Iterator& operator++();
    bool operator==(const iterator_wrapper& other) const;
    bool operator!=(const iterator_wrapper& other) const;
    auto operator*() const;
};

Optional and Variant Support

Support for C++17 optional and variant types.

// std::optional<T> support (include pybind11/stl.h)
// Converts to Python None or the contained value

// std::variant<Ts...> support  
// Automatically selects appropriate Python type based on active variant member

Usage Examples

Automatic STL Conversion

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
#include <map>

namespace py = pybind11;

std::vector<int> create_vector() {
    return {1, 2, 3, 4, 5};
}

void process_vector(const std::vector<std::string>& vec) {
    for (const auto& item : vec) {
        std::cout << item << std::endl;
    }
}

std::map<std::string, int> create_map() {
    return {{"apple", 5}, {"banana", 3}, {"orange", 8}};
}

PYBIND11_MODULE(example, m) {
    // Automatic conversion - vectors become Python lists
    m.def("create_vector", &create_vector);
    m.def("process_vector", &process_vector);
    
    // Automatic conversion - maps become Python dicts
    m.def("create_map", &create_map);
}

Explicit Container Binding

#include <pybind11/pybind11.h>
#include <pybind11/stl_bind.h>
#include <vector>

namespace py = pybind11;

PYBIND11_MODULE(example, m) {
    // Bind vector as a Python class
    py::bind_vector<std::vector<int>>(m, "VectorInt");
    py::bind_vector<std::vector<std::string>>(m, "VectorString");
    
    // Bind map as a Python class
    py::bind_map<std::map<std::string, int>>(m, "MapStringInt");
    
    // Custom container with additional methods
    py::class_<std::vector<double>>(m, "VectorDouble")
        .def(py::init<>())
        .def("push_back", &std::vector<double>::push_back)
        .def("size", &std::vector<double>::size)
        .def("__len__", &std::vector<double>::size)
        .def("__iter__", [](const std::vector<double> &v) {
            return py::make_iterator(v.begin(), v.end());
        }, py::keep_alive<0, 1>());
}

Working with Nested Containers

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;

// Nested container function
std::vector<std::vector<int>> create_matrix(int rows, int cols) {
    std::vector<std::vector<int>> matrix(rows, std::vector<int>(cols, 0));
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j) {
            matrix[i][j] = i * cols + j;
        }
    }
    return matrix;
}

// Complex nested structure
std::map<std::string, std::vector<std::pair<int, double>>> complex_data() {
    return {
        {"series1", {{1, 1.1}, {2, 2.2}, {3, 3.3}}},
        {"series2", {{10, 10.1}, {20, 20.2}, {30, 30.3}}}
    };
}

PYBIND11_MODULE(example, m) {
    m.def("create_matrix", &create_matrix);
    m.def("complex_data", &complex_data);
}

Smart Pointer Containers

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <memory>
#include <vector>

namespace py = pybind11;

class Widget {
public:
    Widget(const std::string& name) : name_(name) {}
    const std::string& name() const { return name_; }
private:
    std::string name_;
};

std::vector<std::shared_ptr<Widget>> create_widgets() {
    return {
        std::make_shared<Widget>("widget1"),
        std::make_shared<Widget>("widget2"),
        std::make_shared<Widget>("widget3")
    };
}

PYBIND11_MODULE(example, m) {
    py::class_<Widget>(m, "Widget")
        .def(py::init<const std::string&>())
        .def("name", &Widget::name);
    
    // Automatic conversion of vector of shared_ptr
    m.def("create_widgets", &create_widgets);
}

Custom Iterator Example

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;

class NumberGenerator {
    int current_, max_;
public:
    NumberGenerator(int max) : current_(0), max_(max) {}
    
    // Make it iterable
    NumberGenerator& iter() { return *this; }
    int next() {
        if (current_ >= max_) throw py::stop_iteration();
        return current_++;
    }
};

PYBIND11_MODULE(example, m) {
    py::class_<NumberGenerator>(m, "NumberGenerator")
        .def(py::init<int>())
        .def("__iter__", &NumberGenerator::iter, 
             py::return_value_policy::reference_internal)
        .def("__next__", &NumberGenerator::next);
}

Performance Considerations

Automatic vs Explicit Binding

// Automatic conversion (pybind11/stl.h)
// Pros: Simple, works out of the box
// Cons: Always copies data, memory overhead

std::vector<int> get_data() { return large_vector; }  // Always copies

// Explicit binding (pybind11/stl_bind.h)  
// Pros: Direct access, no copying, Python-like interface
// Cons: More setup required

py::bind_vector<std::vector<int>>(m, "VectorInt");  // Direct access

Return Value Policies with Containers

class DataManager {
    std::vector<double> data_;
public:
    // Return reference to avoid copying
    const std::vector<double>& get_data() const { return data_; }
    std::vector<double>& get_mutable_data() { return data_; }
};

PYBIND11_MODULE(example, m) {
    py::class_<DataManager>(m, "DataManager")
        .def("get_data", &DataManager::get_data,
             py::return_value_policy::reference_internal)
        .def("get_mutable_data", &DataManager::get_mutable_data,
             py::return_value_policy::reference_internal);
}

Types

namespace pybind11 {
    // Container binding functions (from stl_bind.h)
    template<typename Vector, typename... Options>
    class_<Vector> bind_vector(module_ &m, const char *name, const Options&... options);
    
    template<typename Map, typename... Options>
    class_<Map> bind_map(module_ &m, const char *name, const Options&... options);
    
    template<typename Deque, typename... Options>
    class_<Deque> bind_deque(module_ &m, const char *name, const Options&... options);
    
    // Iterator utilities
    template<typename Iterator>
    class iterator_wrapper;
    
    template<typename Iterator>
    auto make_iterator(Iterator first, Iterator last);
    
    template<typename Iterator> 
    auto make_key_iterator(Iterator first, Iterator last);
    
    template<typename Iterator>
    auto make_value_iterator(Iterator first, Iterator last);
}

Install with Tessl CLI

npx tessl i tessl/pypi-pybind11

docs

advanced-features.md

core-binding.md

exception-handling.md

index.md

numpy-integration.md

python-package.md

stl-integration.md

type-system.md

tile.json