Traditionally a tedious process. You have to go through each class and function you want exposed, and specify its header and all its arguments, working with ugly pragmas. Take the below C++ header file for example:
// Header file
#include <iostream>
namespace pp {
class test {
public:
static void output();
int multiply(int value, int by);
template<typename T>
T max(T a, T b) {
return a > b ? a : b;
};
int fieldName;
static int notherName;
};
}
A snippet of wrapped C++ code might look something like this:
# Traditional wrapper
const test_h = "../test.hpp"
type test {.header: test_h, importcpp.} = object
fieldName: cint
notherName: cint
proc output(this: typedesc[test]): void {.header: test_h, importc: "pp::test::output".}
proc multiply(this: test, value, by: cint): cint {.header: test_h, importcpp.}
proc max[T](this: test, a, b: T): T {.header: test_h, importcpp.}
With ClibPP this process becomes much more readable and simpler. It works by parsing out each of the statements below a "class" declaration, generating code similar to the wrapper code provided above. Here's an example of what a ClibPP wrapper for the same code would look like:
# Import "test" class from C++:
import clibpp
namespace pp:
class(test, header: "../test.hpp"):
proc multiply[T](value, by: T): int
proc output: void {.isstatic.}
proc max[T](a, b: T): T
var fieldName, notherName: int
This module also generates dummy "typedesc" parameters for static methods, so static methods can be invoked with their prefix similar to how they're invoke in C++, i.e. test.output().
Here's what using your wrapper would then look like:
# Use the "test" class from C++:
test.output()
var item: test
echo item.multiply(5, 9)
echo item.fieldName
echo item.max(2, 10)
echo item.notherName