boost python overload operator () - binding

I would like to bind the operator() using Boost::Python but I don't really see how to do this. Consider the example:
C++:
class Queuer
{
public:
void Queuer::operator()(const qfc::Queue & iq, const qfc::Message & im) const;
void Queuer::operator()(const qfc::Agent & ia, const qfc::Message & im) const;
// some other overloaded operator() methods
};
So in a Python script, after importing the module I'm using (called qfc), I would like to do:
Python:
>>> queuer = qfc.Queuer()
// instantiating a Message an Agent and a Queue object
>>> queuer(queue,message)
>>> queuer(agent,message)
>>> ...
Would you have any idea on how to do it? maybe with boost::python call<>?
Thank you,
Kevin

When exposing the Queuer class, define a __call__ method for each Queuer::operator() member function. Boost.Python will handle the appropriate dispatching based on types. The only complexity is introduced with pointer-to-member-function syntax, as the caller is required to disambiguate &Queuer::operator().
Additionally, when attempting to pass derived classes in Python to a C++ function with a parameter of the Base class, then some additional information needs to be exposed to Boost.Python:
The base C++ class needs to be exposed with class_. For example, class_<BaseType>("Base").
The derived class needs to explicitly list its base classes when being exposed with bases_. For example, class_<DerivedType, bases<BaseType> >("Derived"). With this information, Boost.Python can do proper casting while dispatching.
Here is a complete example:
#include <iostream>
#include <boost/python.hpp>
// Mockup classes.
struct AgentBase {};
struct MessageBase {};
struct QueueBase {};
struct SpamBase {};
struct Agent: AgentBase {};
struct Message: MessageBase {};
struct Queue: QueueBase {};
struct Spam: SpamBase {};
// Class with overloaded operator().
class Queuer
{
public:
void operator()(const AgentBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Agent." << std::endl;
}
void operator()(const QueueBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Queue." << std::endl;
}
void operator()(const SpamBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Spam." << std::endl;
}
};
/// Depending on the overlaod signatures, helper types may make the
/// code slightly more readable by reducing pointer-to-member-function syntax.
template <typename A1>
struct queuer_overload
{
typedef void (Queuer::*type)(const A1&, const MessageBase&) const;
static type get(type fn) { return fn; }
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose only the base class types. Do not allow the classes to be
// directly initialized in Python.
python::class_<AgentBase >("AgentBase", python::no_init);
python::class_<MessageBase>("MessageBase", python::no_init);
python::class_<QueueBase >("QueueBase", python::no_init);
python::class_<SpamBase >("SpamBase", python::no_init);
// Expose the user types. These classes inerit from their respective
// base classes.
python::class_<Agent, python::bases<AgentBase> >("Agent");
python::class_<Message, python::bases<MessageBase> >("Message");
python::class_<Queue, python::bases<QueueBase> >("Queue");
python::class_<Spam, python::bases<SpamBase> >("Spam");
// Disambiguate via a varaible.
queuer_overload<AgentBase>::type queuer_op_agent = &Queuer::operator();
python::class_<Queuer>("Queuer")
// Disambiguate via a variable.
.def("__call__", queuer_op_agent)
// Disambiguate via a helper type.
.def("__call__", queuer_overload<QueueBase>::get(&Queuer::operator()))
// Disambiguate via explicit cast.
.def("__call__",
static_cast<void (Queuer::*)(const SpamBase&,
const MessageBase&) const>(
&Queuer::operator()))
;
}
And its usage:
>>> import example
>>> queuer = example.Queuer()
>>> queuer(example.Agent(), example.Message())
Queuer::operator() with Agent.
>>> queuer(example.Queue(), example.Message())
Queuer::operator() with Queue.
>>> queuer(example.Spam(), example.Message())
Queuer::operator() with Spam.

Thanks for your help.
Actually I've already tested the static cast solution. In reality, I need to pass a qfc::lqs::Message or qfc::lqs::Agent or qfc::lqs::Spam when invoking queuer(). qfc::lqs::Message for example, as for qfc::lqs::Agent inherit from qfc::Message and qfc::Agent respectively.
So can I "cast" qfc::lqs::Message, qfc::lqs::Agent and qfc::lqs::Spam to qfc::Message, qfc::Agent and qfc::Spam when invoking the operator() so that the signature corresponds to operator() ?
This to avoid the error shown below:
error: invalid static_cast from type '<unresolved overloaded function type>' to type 'void (qfc::lqs::Queuer::*)(const qfc::lqs::Queue&, const qfc::lqs::Message&)const'

Related

why can't I pass an l-value to a template class constructor that uses universal references?

I have a templated class MyClass<T> that takes some iterable containing ints (e.g. T = std::vector<int>) in its constructor and does something with it.
I would like to be able to pass the iterable as either a temporary object (e.g. MyClass(std::vector<int>{3,6,9}) or similar r-value argument) or from a named variable (resulting in an l-value as the constructor argument).
I would like to use C++17 template class inference (i.e. write MyClass(...), not MyClass<std::vector<int>>(...)).
I thought that I could declare the constructor parameter as MyClass(T && vec) (a "universal reference") to take either an l-value or an r-value (just like I can with functions), but it gives an error. It seems like T is always inferred as std::vector<int> and never std::vector<int>& with classes, whereas functions infer std::vector<int>& when the argument is an l-value.
How exactly are the rules for template constructor inference and template function inference different? Can I avoid having to use a wrapper function (e.g. myFunction(T&&vec) { return MyClass<T>(std::forward<T>(vec)); }) just for the sake of template inference?
Run the code below on Godbolt:
#include <iostream>
#include <utility>
#include <vector>
template <typename T>
using BeginType = decltype(std::declval<T>().begin());
template <typename T>
struct MyClass {
BeginType<T> begin;
BeginType<T> end;
MyClass(T && vec) {
begin = std::forward<T>(vec).begin();
end = std::forward<T>(vec).end();
}
int sum() {
int sum = 0;
for (auto it = begin; it != end; ++it) sum += *it;
return sum;
}
};
template <typename T>
MyClass<T> myFunction(T && vec) {
return MyClass<T>(std::forward<T>(vec));
}
int main() {
std::vector<int> x{1, 2, 3};
std::vector<int> y{2, 4, 6};
// Warmup: Passing r-values works fine
std::cout << MyClass(std::vector<int>{3, 6, 9}).sum() << std::endl; // works fine: T is std::vector<int>
std::cout << MyClass(std::move(y)).sum() << std::endl; // works fine: T is std::vector<int>
// Unexpected: Passing l-values doesn't work
// std::cout << MyClass(x).sum() << std::endl; // error: cannot bind rvalue reference of type 'std::vector<int>&&' to lvalue of type 'std::vector<int>'
// Compare: Passing l-values to function works fine
std::cout << myFunction(x).sum() << std::endl; // works fine: T is std::vector<int>&
}
Add a user-defined deduction guide after the class definition:
template <typename T>
struct MyClass {
// same as in question
};
template <typename TT> MyClass(TT && vec) -> MyClass<TT>;
See also How to write a constructor for a template class using universal reference arguments in C++

store a lambda that captures this

Using C++ 17, I'm looking for a way to store a lambda that captures the this pointer, without using std::function<>. The reason to not using std::function<> is that I need the guaranty that no dynamic memory allocations are used. The purpose of this, is to be able to define some asynchronous program flow. Example:
class foo {
public:
void start() {
timer(1ms, [this](){
set_pin(1,2);
timer(1ms, [this](){
set_pin(2,1);
}
}
}
private:
template < class Timeout, class Callback >
void timer( Timeout to, Callback&& cb ) {
cb_ = cb;
// setup timer and call cb_ one timeout reached
...
}
??? cb_;
};
Edit: Maybe it's not really clear: std::function<void()> would do the job, but I need / like to have the guaranty, that no dynamic allocations happens as the project is in the embedded field. In practice std::function<void()> seems to not require dynamic memory allocation, if the lambda just captures this. I guess this is due to some small object optimizations, but I would like to not rely on that.
You can write your own function_lite to store the lambda, then you can use static_assert to check the size and alignment requirements are satisfied:
#include <cstddef>
#include <new>
#include <type_traits>
class function_lite {
static constexpr unsigned buffer_size = 16;
using trampoline_type = void (function_lite::*)() const;
trampoline_type trampoline;
trampoline_type cleanup;
alignas(std::max_align_t) char buffer[buffer_size];
template <typename T>
void trampoline_func() const {
auto const obj =
std::launder(static_cast<const T*>(static_cast<const void*>(buffer)));
(*obj)();
}
template <typename T>
void cleanup_func() const {
auto const obj =
std::launder(static_cast<const T*>(static_cast<const void*>(buffer)));
obj->~T();
}
public:
template <typename T>
function_lite(T t)
: trampoline(&function_lite::trampoline_func<T>),
cleanup(&function_lite::cleanup_func<T>) {
static_assert(sizeof(T) <= buffer_size);
static_assert(alignof(T) <= alignof(std::max_align_t));
new (static_cast<void*>(buffer)) T(t);
}
~function_lite() { (this->*cleanup)(); }
function_lite(function_lite const&) = delete;
function_lite& operator=(function_lite const&) = delete;
void operator()() const { (this->*trampoline)(); }
};
int main() {
int x = 0;
function_lite f([x] {});
}
Note: this is not copyable; to add copy or move semantics you will need to add new members like trampoline and cleanup which can properly copy the stored object.
There is no drop in replacement in the language or the standard library.
Every lambda is a unique type in the typesystem. Technically you may have a lambda as a member, but then its type is fixed. You may not assign other lambdas to it.
If you really want to have an owning function wrapper like std::function, you need to write your own. Actually you want a std::function with a big enough small-buffer-optimization buffer.
Another approach would be to omit the this capture and pass it to the function when doing the call. So you have a captureless lambda, which is convertible to a function pointer which you can easily store. I would take this route and adapter complexer ways if really nessessary.
it would look like this (i trimmed down the code a bit):
class foo
{
public:
void start()
{
timer(1, [](foo* instance)
{
instance->set_pin(1,2);
});
}
private:
template < class Timeout, class Callback >
void timer( Timeout to, Callback&& cb )
{
cb_ = cb;
cb_(this); // call the callback like this
}
void set_pin(int, int)
{
std::cout << "pin set\n";
}
void(*cb_)(foo*);
};

Variadic Dispatch Function

I have an interface wherein the types of the parameters mostly encode their own meanings. I have a function that takes one of these parameters. I'm trying to make a function that takes a set of these parameters and performs the function on each one in order.
#include <iostream>
#include <vector>
enum param_type{typeA,typeB};
template <param_type PT> struct Container{
int value;
Container(int v):value(v){}
};
int f(Container<typeA> param){
std::cout<<"Got typeA with value "<<param.value<<std::endl;
return param.value;
}
int f(Container<typeB> param){
std::cout<<"Got typeB with value "<<param.value<<std::endl;
return param.value;
}
My current solution uses a recursive variadic template to delegate the work.
void g(){}
template <typename T,typename...R>
void g(T param,R...rest){
f(param);
g(rest...);
}
I would like to use a packed parameter expansion, but I can't seem to get that to work without also using the return values. (In my particular case the functions are void.)
template <typename...T> // TODO: Use concepts once they exist.
void h(T... params){
// f(params);...
// f(params)...; // Fail to compile.
// {f(params)...};
std::vector<int> v={f(params)...}; // Works
}
Example usage
int main(){
auto a=Container<typeA>(5);
auto b=Container<typeB>(10);
g(a,b);
h(a,b);
return 0;
}
Is there an elegant syntax for this expansion in C++?
In C++17: use a fold expression with the comma operator.
template <typename... Args>
void g(Args... args)
{
((void)f(args), ...);
}
Before C++17: comma with 0 and then expand into the braced initializer list of an int array. The extra 0 is there to ensure that a zero-sized array is not created.
template <typename... Args>
void g(Args... args)
{
int arr[] {0, ((void)f(args), 0)...};
(void)arr; // suppress unused variable warning
}
In both cases, the function call expression is cast to void to avoid accidentally invoking a user-defined operator,.

FatalExecutionEngineError on accessing a pointer set with memcpy_s

See update 1 below for my guess as to why the error is happening
I'm trying to develop an application with some C#/WPF and C++. I am having a problem on the C++ side on a part of the code that involves optimizing an object using GNU Scientific Library (GSL) optimization functions. I will avoid including any of the C#/WPF/GSL code in order to keep this question more generic and because the problem is within my C++ code.
For the minimal, complete and verifiable example below, here is what I have. I have a class Foo. And a class Optimizer. An object of class Optimizer is a member of class Foo, so that objects of Foo can optimize themselves when it is required.
The way GSL optimization functions take in external parameters is through a void pointer. I first define a struct Params to hold all the required parameters. Then I define an object of Params and convert it into a void pointer. A copy of this data is made with memcpy_s and a member void pointer optimParamsPtr of Optimizer class points to it so it can access the parameters when the optimizer is called to run later in time. When optimParamsPtr is accessed by CostFn(), I get the following error.
Managed Debugging Assistant 'FatalExecutionEngineError' : 'The runtime
has encountered a fatal error. The address of the error was at
0x6f25e01e, on thread 0x431c. The error code is 0xc0000005. This error
may be a bug in the CLR or in the unsafe or non-verifiable portions of
user code. Common sources of this bug include user marshaling errors
for COM-interop or PInvoke, which may corrupt the stack.'
Just to ensure the validity of the void pointer I made, I call CostFn() at line 81 with the void * pointer passed as an argument to InitOptimizer() and everything works. But in line 85 when the same CostFn() is called with the optimParamsPtr pointing to data copied by memcpy_s, I get the error. So I am guessing something is going wrong with the memcpy_s step. Anyone have any ideas as to what?
#include "pch.h"
#include <iostream>
using namespace System;
using namespace System::Runtime::InteropServices;
using namespace std;
// An optimizer for various kinds of objects
class Optimizer // GSL requires this to be an unmanaged class
{
public:
double InitOptimizer(int ptrID, void *optimParams, size_t optimParamsSize);
void FreeOptimizer();
void * optimParamsPtr;
private:
double cost = 0;
};
ref class Foo // A class whose objects can be optimized
{
private:
int a; // An internal variable that can be changed to optimize the object
Optimizer *fooOptimizer; // Optimizer for a Foo object
public:
Foo(int val) // Constructor
{
a = val;
fooOptimizer = new Optimizer;
}
~Foo()
{
if (fooOptimizer != NULL)
{
delete fooOptimizer;
}
}
void SetA(int val) // Mutator
{
a = val;
}
int GetA() // Accessor
{
return a;
}
double Optimize(int ptrID); // Optimize object
// ptrID is a variable just to change behavior of Optimize() and show what works and what doesn't
};
ref struct Params // Parameters required by the cost function
{
int cost_scaling;
Foo ^ FooObj;
};
double CostFn(void *params) // GSL requires cost function to be of this type and cannot be a member of a class
{
// Cast void * to Params type
GCHandle h = GCHandle::FromIntPtr(IntPtr(params));
Params ^ paramsArg = safe_cast<Params^>(h.Target);
h.Free(); // Deallocate
// Return the cost
int val = paramsArg->FooObj->GetA();
return (double)(paramsArg->cost_scaling * val);
}
double Optimizer::InitOptimizer(int ptrID, void *optimParamsArg, size_t optimParamsSizeArg)
{
optimParamsPtr = ::operator new(optimParamsSizeArg);
memcpy_s(optimParamsPtr, optimParamsSizeArg, optimParamsArg, optimParamsSizeArg);
double ret_val;
// Here is where the GSL stuff would be. But I replace that with a call to CostFn to show the error
if (ptrID == 1)
{
ret_val = CostFn(optimParamsArg); // Works
}
else
{
ret_val = CostFn(optimParamsPtr); // Doesn't work
}
return ret_val;
}
// Release memory used by unmanaged variables in Optimizer
void Optimizer::FreeOptimizer()
{
if (optimParamsPtr != NULL)
{
delete optimParamsPtr;
}
}
double Foo::Optimize(int ptrID)
{
// Create and initialize params object
Params^ paramsArg = gcnew Params;
paramsArg->cost_scaling = 11;
paramsArg->FooObj = this;
// Convert Params type object to void *
void * paramsArgVPtr = GCHandle::ToIntPtr(GCHandle::Alloc(paramsArg)).ToPointer();
size_t paramsArgSize = sizeof(paramsArg); // size of memory block in bytes pointed to by void pointer
double result = 0;
// Initialize optimizer
result = fooOptimizer->InitOptimizer(ptrID, paramsArgVPtr, paramsArgSize);
// Here is where the loop that does the optimization will be. Removed from this example for simplicity.
return result;
}
int main()
{
Foo Foo1(2);
std::cout << Foo1.Optimize(1) << endl; // Use orig void * arg in line 81 and it works
std::cout << Foo1.Optimize(2) << endl; // Use memcpy_s-ed new void * public member of Optimizer in line 85 and it doesn't work
}
Just to reiterate I need to copy the params to a member in the optimizer because the optimizer will run all through the lifetime of the Foo object. So it needs to exist as long as the Optimizer object exist and not just in the scope of Foo::Optimize()
/clr support need to be selected in project properties for the code to compile. Running on an x64 solution platform.
Update 1: While trying to debug this, I got suspicious of the way I get the size of paramsArg at line 109. Looks like I am getting the size of paramsArg as size of int cost_scaling plus size of the memory storing the address to FooObj instead of the size of memory storing FooObj itself. I realized this after stumbling across this answer to another post. I confirmed this by checking the value of paramsArg after adding some new dummy double members to Foo class. As expected the value of paramsArg doesn't change. I suppose this explains why I get the error. A solution would be to write code to correctly calculate the size of a Foo class object and set that to paramsArg instead of using sizeof. But that is turning out to be too complicated and probably another question in itself. For example, how to get size of a ref class object? Anyways hopefully someone will find this helpful.

Storing multiple types into class member container

I was reading this Q/A here and as my question is similar but different I would like to know how to do the following:
Let's say I have a basic non template non inherited class called Storage.
class Storage {};
I would like for this class to have a single container (unordered multimap) is where I'm leaning towards... That will hold a std::string for a name id to a variable type T. The class itself will not be template. However a member function to add in elements would be. A member function to add might look like this:
template<T>
void addElement( const std::string& name, T& t );
This function will then populate the unorderd multimap. However each time this function is called each type could be different. So my map would look something like:
"Hotdogs", 8 // here 8 is int
"Price", 4.85f // here 4.8f is float.
How would I declare such an unorderd multimap using templates, variadic parameters, maybe even tuple, any or variant... without the class itself being a template? I prefer not to use boost or other libraries other than the standard.
I tried something like this:
class Storage {
private:
template<class T>
typedef std::unorderd_multimap<std::string, T> DataTypes;
template<class... T>
typedef std::unordered_multimap<std::vector<std::string>, std::tuple<T...>> DataTypes;
};
But I can not seem to get the typedefs correct so that I can declare them like this:
{
DataTypes mDataTypes;
}
You tagged C++17, so you could use std::any (or std::variant if the T type can be a limited and know set of types`).
To store the values is simple.
#include <any>
#include <unordered_map>
class Storage
{
private:
using DataTypes = std::unordered_multimap<std::string, std::any>;
DataTypes mDataTypes;
public:
template <typename T>
void addElement (std::string const & name, T && t)
{ mDataTypes.emplace(name, std::forward<T>(t)); }
};
int main()
{
Storage s;
s.addElement("Hotdogs", 8);
s.addElement("Price", 4.85f);
// but how extract the values ?
}
But the problem is that now you have a element with "Hotdogs" and "Price" keys in the map, but you have no info about the type of the value.
So you have to save, in some way, a info about the type of th value (transform the value in a std::pair with some id-type and the std::any?) to extract it when you need it.
I've done something along those lines, the actual solution is very specific to your problem.
That being said, I'm doing this on a vector, but the principle applies to maps, too.
If you're not building an API and hence know all classes that will be involved you could use std::variant something along the lines of this:
#include <variant>
#include <vector>
#include <iostream>
struct ex1 {};
struct ex2 {};
using storage_t = std::variant<ex1, ex2>;
struct unspecific_operation {
void operator()(ex1 arg) { std::cout << "got ex1\n";}
void operator()(ex2 arg) { std::cout << "got ex2\n";}
};
int main() {
auto storage = std::vector<storage_t>{};
storage.push_back(ex1{});
storage.push_back(ex2{});
auto op = unspecific_operation{};
for(const auto& content : storage) {
std::visit(op, content);
}
return 0;
}
which will output:
got ex1
got ex2
If I remember correctly, using std::any will enable RTTI, which can get quite expensive; might be wrong tho.
If you provide more specifics about what you actually want to do with it, I can give you a more specific solution.
for an example with the unordered map:
#include <variant>
#include <unordered_map>
#include <string>
#include <iostream>
struct ex1 {};
struct ex2 {};
using storage_t = std::variant<ex1, ex2>;
struct unspecific_operation {
void operator()(ex1 arg) { std::cout << "got ex1\n";}
void operator()(ex2 arg) { std::cout << "got ex2\n";}
};
class Storage {
private:
using map_t = std::unordered_multimap<std::string, storage_t>;
map_t data;
public:
Storage() : data{map_t{}}
{}
void addElement(std::string name, storage_t elem) {
data.insert(std::make_pair(name, elem));
}
void doSomething() {
auto op = unspecific_operation{};
for(const auto& content : data) {
std::visit(op, content.second);
}
}
};
int main() {
auto storage = Storage{};
storage.addElement("elem1", ex1{});
storage.addElement("elem2", ex2{});
storage.addElement("elem3", ex1{});
storage.doSomething();
return 0;
}

Resources