-
Notifications
You must be signed in to change notification settings - Fork 6
02 Customizing Method Names
Let's expand our simple Hello class to take arguments. And because it's C++ we'll implement different argument types as overloads
#pragma once
#include <iostream>
namespace hello {
class Hello {
public:
void hello(const char* msg) const {
std::cout << "Hello, " << msg << "!\n";
}
void hello(const int msg) const { std::cout << "Hello, " << msg << "!\n"; }
void hello(const float msg) const {
std::cout << "Hello, " << msg << "!\n";
}
};
} // namespace hello
We'll create a new working directory and save this as 02_customizing_methods/include/hello.hpp
.
Next we'll need to update our binding file to match the new method signiatures
#include "hello.hpp"
namespace cppmm_bind {
namespace hello {
struct Hello {
using BoundType = ::hello::Hello;
void hello(const char* msg) const;
void hello(const int msg) const;
void hello(const float msg) const;
};
} // namespace hello
} // namespace cppmm_bind
and we'll save this as 02_customizing_methods/bind/c-hello.cpp
.
If we now generate the AST and the bindings:
./astgen/astgen 02_customizing_methods/bind/c-hello.cpp -v 1 -o 02_customizing_methods/ast -- -I../tutorial/02_customizing_methods/include
./asttoc/asttoc 02_customizing_methods/ast -o 02_customizing_methods -p customizing_methods
and inspect the resulting C header, 02_customizing_methods/customizing_methods-c/c-hello.h
, we can see that asttoc
has renamed the methods for us to avoid name collisions. The names aren't exactly helpful though:
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef struct hello__Hello_t_s {
char data[1];
} __attribute__((aligned(1))) hello__Hello_t;
typedef hello__Hello_t hello_Hello_t;
void hello__Hello_hello(
hello_Hello_t const * this_
, char const * msg);
#define hello_Hello_hello hello__Hello_hello
void hello__Hello_hello_1(
hello_Hello_t const * this_
, int const msg);
#define hello_Hello_hello_1 hello__Hello_hello_1
void hello__Hello_hello_2(
hello_Hello_t const * this_
, float const msg);
#define hello_Hello_hello_2 hello__Hello_hello_2
#ifdef __cplusplus
}
#endif
If you're wondering what those #defines and typedefs that look redundant are there for, that will be explained in tutorial 04. SPOILER: they're there to allow us to provide nice public names for all functions and types, but we haven't set that up yet.
Fortunately, astgen
lets us add attributes to the binding file to tweak the generated binding in a number of ways, including renaming methods. This is done with standard clang/gcc attributes, and they're wrapped up in macros to make them easier to use.
These macros are defined in a virtual file that's injected by astgen
automatically, called cppmm_bind.hpp
, so the first thing to do is to modify the binding file to include this virtual header, and then we can use the CPPMM_RENAME
macro to specify what name we want for each overload. For example:
#include "hello.hpp"
#include <cppmm_bind.hpp>
namespace cppmm_bind {
namespace hello {
struct Hello {
using BoundType = ::hello::Hello;
void hello(const char* msg) const CPPMM_RENAME(hello_string);
void hello(const int msg) const CPPMM_RENAME(hello_int);
void hello(const float msg) const CPPMM_RENAME(hello_float);
};
} // namespace hello
} // namespace cppmm_bind
and re-running the ast and binding generation as above gives us
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef struct hello__Hello_t_s {
char data[1];
} __attribute__((aligned(1))) hello__Hello_t;
typedef hello__Hello_t hello_Hello_t;
void hello__Hello_hello_string(
hello_Hello_t const * this_
, char const * msg);
#define hello_Hello_hello_string hello__Hello_hello_string
void hello__Hello_hello_int(
hello_Hello_t const * this_
, int const msg);
#define hello_Hello_hello_int hello__Hello_hello_int
void hello__Hello_hello_float(
hello_Hello_t const * this_
, float const msg);
#define hello_Hello_hello_float hello__Hello_hello_float
#ifdef __cplusplus
}
#endif
Much better!