Customization

Many customization options of the bindings generation are available, e.g. wrap only some functions and classes, choose template instantiation, and so on. This can be done

  • with code annotations or

  • with (compile time) declarations in the reserved namespace c2py_module.

The choice between the two approaches depends on the project and needs. The latter is more general and non intrusive, but slighly more complex.

Code annotations

clair’s behaviour can be modified by simple annotations in the code.

  • C2PY_IGNORE: Placed before a function or a class, clair ignores it.

  • C2PY_WRAP: Placed before a function or a class, clair keeps it. This can be used in combination with a reject_names filter .*.

These annotations overrule any filter options in c2py_module.

Filters

By default, clair will generate bindings for all non-template classes and functions, except those defined in system files, i.e. the standard library and more generally anything the compiler includes via -isystem options. In order to refine this behaviour, several filters can be used.

  • match_names, reject_names. These regular expressions control which functions/classes/enums are exposed to Python.

    The algorithm to determine if an element X of qualified name Xqname (i.e. the full name with the namespaces) should be exposed is:

    1. if match_names is defined and does not match Xqname then skip X

    2. if reject_names is defined and matches Xqname then skip X

    3. else expose X to Python.

Here is an example:

#include <c2py/c2py.hpp>

int g() { return 8; }

namespace N {
  int f(int x) { return -x; }

  struct a_class {
    // ...
  };

  struct hidden {
    //...
  };
} // namespace N

namespace c2py_module {
  auto match_names  = "N::.*";     // match functions and names in namespace N
  auto reject_names = "N::hidden"; // reject the specific name "hidden" in namespace N
} // namespace c2py_module

In this example, the function f and the struct a_class are exposed to Python, while the function g, and the struct N::hidden are not.

Warning

Be careful that these strings are Regex. For example, N::* does not match N::f. Also note that the qualified name starts with ::. So to match the start of a name, use ^::N::f.

Template instantiation. Explicitly wrapping a function

In addition to the functions automatically detected by clair, one can explicitly declare some functions to be wrapped in the c2py_module::add namespace using the c2py::dispatch type. This is specially useful for template instantiation.

#include <c2py/c2py.hpp>

int f(auto x) { return 1; } // a generic (template) function

namespace c2py_module {
  // ...
  namespace add {
    // function f in python dispatching the 2 instantiations.
    auto f = c2py::dispatch<::f<int>, ::f<double>>;
  } // namespace add
} // namespace c2py_module

Since the function f is a template, no automatic wrapping will happen by default, as the compiler can not know which instantiations to use. The declaration auto f =... adds a Python function f (the name of the declaration) which consists in dispatching f<int> and f<double>.

  • c2py::dispatch<list of function pointers>

    Declares a list of C++ functions to be dispatched together

Note

Any function pointer can be used in c2py::dispatch, so the same technique can be used to regroup different functions into one dispatch, or rename a function.

Class template instantiation

Similar to functions, instantiations of class templates should be declared with a using command in the c2py_module::add namespace and a Python name should be provided:

#include <c2py/c2py.hpp>

template <typename T> struct A {
  T x;
};

namespace c2py_module {
  // ...
  namespace add {
    using Ai = A<int>;
    using Ad = A<double>;
  } // namespace add
} // namespace c2py_module

In this example, the Python classes Ai and Ad wrap the C++ classes A<int> and A<double>, respectively.

Modifying classes

To be documented.

Misc

Additional information can be provided:

 1namespace c2py_module {
 2
 3  // Name of the package if any. Default is ""
 4  auto package_name = "Package"; // the module will be Package.MyModule
 5
 6  // The documentation string of the module. Default = ""
 7  auto documentation = "Module documentation";
 8
 9  // An function (or lambda) `module_init` to be executed at the start of the module
10  // Signature must be () -> void
11  auto module_init = []() {};
12
13} // namespace c2py_module