I'm using boost-python to create python bindings for a C++ class named CppClass. When necessary, I can route calls to "normal" member functions through little wrapper functions that preprocess the arguments (e.g. extract C++ types from the python args), like so:
class CppClass
{
public:
CppClass(SpecialParameters p);
void doSomething(int x, float y);
};
using namespace boost::python; // For extract, tuple, init, class_, etc.
class WrapperFuncs
{
public:
static void doSomething(CppClass & c, tuple t)
{
// Special extraction: Convert python arg ( a tuple) into C++ args.
int x = extract<int>(t.attr("__getitem__")(0));
float y = extract<float>(t.attr("__getitem__")(1));
c.doSomething(x,y);
}
};
class_<CppClass, boost::shared_ptr<CppClass> >
("CppClass", init<SpecialParameters>())
.def("doSomething", &WrapperFuncs::doSomething, (arg("t")))
But how do I do the same for the CppClass constructor?
Use no_init followed by a .def for __init__ using boost::python::make_constructor().
class WrapperFuncs
{
public:
static boost::shared_ptr<CppClass> initWrapper( object const & p )
{
SpecialParameters sp = ... // do complicated extraction here.
return boost::shared_ptr<CppClass>( new CppClass(sp) );
}
static void doSomething(CppClass & c, tuple t) { /*...*/ }
};
class_<CppClass, boost::shared_ptr<CppClass> >
("CppClass", no_init)
.def("__init__", make_constructor(&WrapperFuncs::initWrapper))
.def("doSomething", &WrapperFuncs::doSomething, (arg("t")))
This section of the python wiki explains how to do this, but it didn't quite work for me because it didn't mention no_init. In my case, no_init was required.
Related
What is considered to be best or good practice when declaring type aliases for function types in C++ (I know this part of the question is probably subjective)? Either
using FuncType = void(int, int);
or
using FuncType = std::function<void(int, int)>;
Are there benefits of one over the other?
How should I use these types as function arguments (when passing as functor, lambda, member or global function), for example
void foo(FuncType&& func) { ... }
void foo(FuncType func) { ... }
void foo(std::function<FuncType> func) { ... }
EDIT
I know that not all of my examples above are applicable with both #1 and #2 but that is not the point. I want to know which (and why) option is better and how should I pass this type when using it as a function argument.
Specific use case
As it appears to be too broad (which I absolutely understand) I'm going to give more detail about my specific case.
I have a class that holds a vector of functions that I want to call (most likely parallel, but I don't think this matters). In this class I can add functions to the vector at runtime.
For example:
class
Container
{
public:
using FuncType = std::function<void(const SomeComplexDataType&, int, double)>;
inline void addFunction(FuncType func)
{
_funcs.push_back(func);
}
inline void call(const SomeComplexDataType& a, int b, double c)
{
for (auto& func : _funcs)
func(a, b, c);
}
private:
std::vector<FuncType> _funcs{};
};
struct HeavyFunctor
{
// contains some heavy objects
void operator()(const SomeComplexDataType& a, int b, double c)
{
/* Some heavy workload */
}
};
int main()
{
Container c;
c.addFunction([](const SomeComplexDataType& a, int b, double c) { /* do something lightweight */ });
c.addFunction(HeavyFunctor);
c.call(x, y, z);
return 0;
}
How should I define FuncType and the parameter for addFunction and how can I store them in the vector (in a best case scenario, without copying the callables)?
I'd personnaly use:
typedef std::function<void(int,int)> FuncType;
and
void foo(const FuncType &func) { ... }
edit:
Not the best for performance considering comment on this post as it requires virtual dispatch.
Working on a command line parser for myself. I knew immediately that I was going to have trouble with this construct and hoping someone could provide suggestions for a work around.
I want to store the argument list of parameters (based off a template) in a vector that will possibly contain a variety of different data types. But from my understanding, you have to define the vector<template<type>> statically. Is there a way to except multiple types?
Here is an example of what I mean:
#include <vector>
#include <memory>
namespace clparser
{
class CommandLine {
private:
std::vector<Parameter<AnyType??>*> ArgumentList;
public:
void Add(Parameter<AnyType??>* Parameter) { ArgumentList.push_back(Parameter); }
};
template<typename T>
class Parameter {
private:
const char *ShortOption;
const char *LongOption;
const char *Description;
const bool RequiredField;
const char *DefaultValue;
public:
Parameter(const char *ShortOption, const char *LongOption, const char *Description, const bool RequiredField, const char *DefaultValue)
: ShortOption(ShortOption), LongOption(LongOption), Description(Description), RequiredField(RequiredField), DefaultValue(DefaultValue)
{
}
};
}
If you can accept a C++11 solution, I propose you a iper-simplified version from my command line parser. Hoping that can be of inspiration for you.
The idea behind my solution is the use of base/derived polymorphism: a pure virtual class optBase that is a base for a set of template classes dedicated to options (in the following example, only class opt; but there are other three in my parser).
Then the (not template) class yData contain a std::unique_ptr<optBase> (if you use a simple pointer to optBase you can compile in C++98 too, I suppose; but I suggest the use of C++11 or newer).
class yData correspond (roughly) to your tou your class Parameter but (here is the trick) isn't a template class; contain a base pointer to a template class.
My class yarg correspond to your class clparser and my std::map<int, yData> idMap correspond (roughly) to your std::vector<Parameter<AnyType??>*> ArgumentList.
To feed idMap, I've developed a set of template method (one for every derived from optbase classes); in the following example you can see a iper-semplified version of one of them: addOpt() (corresponding, roughly, to your Add()).
In the following example you can see a little main() with a couple of uses for addOpt(): the first for a int parameter and the second for a double parameter (important (and weak point of my solution): the returned value must be saved in a reference variable, not in a simple variable).
#include <map>
#include <memory>
class optBase
{
public:
// some pure virtual methods
};
template <typename X>
class opt : public optBase
{
private:
X val { };
// ...
public:
opt ()
{ }
opt (X const & v0)
: val { v0 } // ...
{ }
X const & getVal () const
{ return val; }
X & getVal ()
{ return val; }
// ...
};
// other optBase derived classes (for flags, containers of values, etc)
class yData
{
private:
// ...
std::unique_ptr<optBase> optB;
public:
yData (/* other arguments */ std::unique_ptr<optBase> optB0)
: /* something else */ optB { std::move(optB0) }
{ }
// ...
std::unique_ptr<optBase> const & getPnt () const
{ return optB; }
};
class yarg
{
private:
// ...
std::map<int, yData> idMap;
// ...
public:
// ...
template <typename T>
T & addOpt (/* other arguments */ T const & def = T())
{
int id { /* some value */ };
opt<T> * optP { nullptr };
// ...&
idMap.emplace(std::piecewise_construct,
std::forward_as_tuple(id),
std::forward_as_tuple(/* other arguments */
std::unique_ptr<optBase>(optP = new opt<T>(def))));
return optP->getVal();
}
};
int main ()
{
yarg y;
// important: use a *reference*
auto & pi = y.addOpt(3); // pi is a int
auto & pd = y.addOpt(3.0); // pd is a double
static_assert(std::is_same<decltype(pi), int &>::value, "!");
static_assert(std::is_same<decltype(pd), double &>::value, "!!");
}
I wrote a C++ class that parses expressions like "2 * SQRT(5) + 1". I've created a class called c_function that "represents" the usual mathematical functions like sqrt, sin, cos etc. something like as follows:
class c_function {
std::string name;
double (*function)(double);
public:
c_function(std::string fname, double (*ffunction)(double)) {
name = fname;
function = ffunction;
}
// ...
};
Then I have a different class that contains a std::vector of these c_function objects:
class expression {
std::vector<c_function> functions;
// etc...
public:
// ctor:
expression(/* ... */) {
// ...
functions.push_back(c_function("SQRT", sqrt));
functions.push_back(c_function("SIN" , sin));
functions.push_back(c_function("COS" , cos));
// ...
}
};
The point is that all these functions have one argument. That is fine for most cases but I want to enable adding custom functions to the expression class and also want to support custom functions with more that one argument (for example, to define a function AREA(a, b) that returns the product of the two values a and b).
I did that by adding an argument counter argumentCount and more function "properties" to the c_function class:
class c_function {
std::string name;
unsigned int argumentCount;
double (*function1)(double);
double (*function2)(double, double);
// ...
};
and used two constructors:
c_function(std::string fname, double (*ffunction)(double)) {
name = fname;
argumentCount = 1;
function1 = ffunction;
function2 = NULL;
};
c_function(std::string fname, double (*ffunction)(double, double)) {
name = fname;
argumentCount = 2;
function1 = NULL;
function2 = ffunction;
};
and added the methods to the expression class:
// add custom function with one argument
void addFunction(std::string fname, double (*ffunction)(double));
// add custom function with two arguments
void addFunction(std::string fname, double (*ffunction)(double, double));
so that one can define
double Expression_Area(double width, double height) {
return (width * height);
}
and introduce it to the expression class with
myExpression.addFunction("AREA", Expression_Area);
That works fine and this way I can also add more function "properties" and functions constructors allowing any number of arguments, but
there is always a limit of the number of arguments that is supported
the code becomes ugly by having multiple constructors, methods to add a function, and code within the interpretation of the expression just because the number of arguments may be different.
I wonder if there is a way to support functions with any number of arguments more general. I tried changing the c_function class to:
class c_function {
std::string name;
unsigned int argumentCount;
double (*function)(...);
// ...
};
but this does not work because functions with fixed number of arguments are not accepted by (...).
Is there any way to get this solved with one constructor, one function "property" etc.?
C++11 onwards
In C++11 you can use a variadic template to declare a class that will take a function with a variable number of arguments:
#include <iostream>
#include <string>
double bar(double x) {
return x;
}
double bar2(double x, double y) {
return x+y;
}
template <typename... Args>
class Foo {
public:
Foo (const std::string& name, double (*func)(Args...))
: name_{name}, func_{func} {}
double call(Args... args) {
return func_(args...);
}
// Thanks to W.F. for reminding me of the operator() overload
// This does the same thing as a call to the "call" method.
double operator()(Args... args) {
return func_(args...);
}
private:
std::string name_;
double (*func_)(Args...);
};
int main() {
Foo<double> t1("test1", bar);
Foo<double, double> t2("test2", bar2);
// NOTE: in C++17 you can declare Foo without the template
// arguments: they will be deduced.
// Foo t1("test1", bar); // C++17
// Foo t2("test2", bar2); // C++17
std::cout << t1.call(14) << ' ' << t2(14, 56) << std::endl;
return 0;
}
You can tweak this basic solution as to how you need your classes to work.
C++98
Pre C++11, you will probably be forced to create classes that take functions with a different number of arguments, so your classes would look something like this:
#include <iostream>
#include <string>
double bar(double x) {
return x;
}
double bar2(double x, double y) {
return x+y;
}
class Foo1 {
public:
// let's typedef the function pointer for two reasons:
// 1. readability
// 2. duplicating the class for a different number of arguments
// means we need to do less modifications to the code because
// we can catch a few changes in one line here.
typedef double (*Function)(double);
Foo1 (const std::string& name, const Function func)
: name_(name), func_(func) {}
double operator()(double x) {
return func_(x);
}
private:
std::string name_;
Function func_;
};
class Foo2 {
public:
typedef double (*Function)(double, double);
Foo2 (const std::string& name, const Function func)
: name_(name), func_(func) {}
double operator()(double x, double y) {
return func_(x, y);
}
private:
std::string name_;
Function func_;
};
// etc. for classes Foo3, Foo4, ... up until you think you will
// need no more.
int main() {
Foo1 t1("test1", bar);
Foo2 t2("test2", bar2);
std::cout << t1(14) << ' ' << t2(14, 56) << std::endl;
return 0;
}
There's a bit of code duplication here, but it's not too bad.
Remarks
Finally, (although I did not show it above because I think it goes without saying) wherever there is code duplication, template the types so that you can reduce this as much as possible. So, for example, you might consider modifying the C++11 Foo class above to:
template <typename T, typename... Args>
class Foo {
public:
typedef T (*Function)(Args...);
Foo (const std::string& name, const Function func)
: name_{name}, func_{func} {}
T operator()(Args... args) {
return func_(args);
}
private:
std::string name_;
Function func_;
};
I'm trying to use std::bind and typecast the function arguments to use with a typedef function. However, I can't typecast the std::placeholder. Any ideas to implement what I'm trying to do? For varied reasons, I need to be able to have the typedef function have a uint16_t argument, and also have the init function accept a member function that takes a uint8_t argument). The code (edited for simplicity) that I'm using:
typedef void (write_func_t) (uint16_t, uint8_t);
class MyClass {
public:
MyClass();
template < typename T >
void init(void (T::*write_func)(uint8_t, uint8_t), T *instance) {
using namespace std::placeholders;
_write_func = std::bind(write_func, instance, (uint16_t)_1, _2);
this->init();
}
private:
write_func_t *_write_func;
};
Wouldn't this be cleaner (and much simpler using lambdas and std::function<>)?
class MyClass {
using WriteFunc = std::function<void(int16_t, int8_t)>;
public:
void init(WriteFunc&& func) {
write_func_ = std::move(func);
}
private:
WriteFunc write_func_;
};
Then call in some other type..
class Foo {
// e.g
void SomeWriteFunction(int8_t x, int8_t y) {
}
void bar() {
// The lambda wraps the real write function and the type conversion
mc_inst.init([this](int16_t x, int8_t y) {
this->SomeWriteFunction(x, y);
});
}
};
what's the right way to export template function from c++ into python using boost.python? Here is the code:
template<typename T>
T getValue(const std::string &key, const T &defaultValue = T()) {}
// Export into some python class:
class_<ConfigManager>(...)
.def("GetValue", getValue<int>)
.def("GetValue", getValue<float>)
.def("GetValue", getValue<std::string>);
And usage:
print GetValue("width")
Boost.Python.ArgumentError: Python argument types in
GetValue(ConfigManager, str)
did not match C++ signature:
GetValue(ConfigManager {lvalue}, std::string, int)
What's wrong?
You should read the relevant Boost documentation regarding default arguments. I'll summarize below.
The problem here is that default arguments are used when calling functions in C++. Get rid of them and you'll see the problem from Python's perspective:
// this function *must* be called with two parameters
template<typename T>
T getValue(const std::string &key, const T &defaultValue) {}
class_<ConfigManager>(...)
.def("GetValue", getValue<int>) // two arguments!
.def("GetValue", getValue<float>) // Python has no idea about the defaults,
.def("GetValue", getValue<std::string>); // they are a C++ feature for calling
The fundamental issue is that function types don't carry default argument information. So how can we simulate it? Essentially, by overloading:
template<typename T>
T getValue(const std::string &key, const T &defaultValue) {}
template<typename T>
T getValueDefault(const std::string &key)
{
// default available in C++,
// transitively available in Python
return getValue(key);
}
class_<ConfigManager>(...)
.def("GetValue", getValue<int>) // two arguments
.def("GetValue", getValueDefault<int>) // one argument
// and so on
A maintenance hassle. Luckily, Boost makes this easy:
template<typename T>
T getValue(const std::string &key, const T &defaultValue) {}
// creates utility class x, which creates overloads of function y,
// with argument count as low as a and as high as b:
// BOOST_PYTHON_FUNCTION_OVERLOADS(x, y, a, b);
BOOST_PYTHON_FUNCTION_OVERLOADS(getValueIntOverloads, getValue<int>, 1, 2);
class_<ConfigManager>(...)
.def("GetValue", getValue<int>, getValueIntOverloads()) // one or two arguments
// and so on
The macro also exists for class members. This is in the documentation, if any of it is unclear.
You can also add another template for your class so that you don't have to write/instantiate for each int/float type.
template<typename LinksT>
class Base {
public:
virtual ~Base() {}
virtual Base* x() = 0;
};
#include <boost/python.hpp>
using namespace boost::python;
template<typename LinksT>
class BaseWrap : public Base<LinksT>, public wrapper<Base<LinksT> > {
public:
virtual Base<LinksT>* x() { return this->get_override("x")(); }
};
template<typename LinksT>
void export_virtualfunction()
{
class_<BaseWrap<LinksT>, boost::noncopyable>("Base", no_init)
.def("x", pure_virtual(&Base<LinksT>::x), return_internal_reference<>())
;
}
BOOST_PYTHON_MODULE(test_template_python)
{
export_virtualfunction<int>();
}