Replacing dynamic polymorphy with static polymorphy in C++ - variadic-templates

Motivated due to the fact, that the avr-g++ places the vtables in RAM, I wrote a replacement using static polymorphy.
Consider the following example:
volatile uint8_t x;
struct IX {
virtual void f() const = 0;
// virtual ~IX() = default; // need delete
};
struct A : public IX {
const uint8_t v = 0;
void f() const override {
x = v;
}
};
struct B : public IX {
const uint8_t v = 1;
void f() const override {
x = v;
}
};
struct C : public IX {
const uint8_t v = 2;
void f() const override {
x = v;
}
};
volatile uint8_t index = 2;
int main() {
A a;
B b;
C c;
const std::array<const IX*, 3> cc{&a, &b, &c};
cc[index]->f();
while(true) {}
}
Here we have some types A, B and C implementing an interface IX and placing pointers in the array cc. Then we call the virtual function f() for a specific instance. (Using this on a small µC like the AVRs, there is a "waste" of RAM, since the vtables are placed in RAM and each object contains a vptr, and a performance penalty due to the indirect call of f().
So I looked for an alternative solution in this case: the simplest way is to use an heterogenous container like std::tuple and write a switch-statement:
const std::tuple<A, B, C> t;
auto f = [](const auto& v) {
v.f();
};
switch (index) {
case 0:
f(std::get<0>(t));
break;
case 1:
f(std::get<1>(t));
break;
case 2:
f(std::get<2>(t));
break;
default:
assert(false);
break;
}
This yields to optimale machine-code but it is an unflexible solution. So I wrote a metafunction to call f() for a specific element of the tuple:
const std::tuple<A, B, C> t;
Meta::visitAt(t, index, [](const auto& v){v.f();});
And the implementation looks like:
namespace Meta {
namespace detail {
template<uint8_t N>
struct visit {
template<typename T, typename F>
static void at(T& tuple, uint8_t index, const F& f) {
if (index == (N - 1)) {
f(std::get<N - 1>(tuple));
}
else {
visit<N - 1>::at(tuple, index, f);
}
}
};
template<>
struct visit<0> {
template<typename T, typename F>
static void at(T&, uint8_t , const F&) {
assert(false);
}
};
template<typename T, typename F, size_t... I>
void all(const T& tuple, const F& f, std::index_sequence<I...>) {
(f(std::get<I>(tuple)), ...);
}
}
template<typename... T, typename F>
void visitAt(const std::tuple<T...>& tuple, uint8_t index, const F& f) {
detail::visit<sizeof...(T)>::at(tuple, index, f);
}
template<typename... T, typename F>
void visitAt(std::tuple<T...>& tuple, uint8_t index, const F& f) {
detail::visit<sizeof...(T)>::at(tuple, index, f);
}
template<typename... T, typename F>
void visit(const std::tuple<T...>& tuple, const F& f) {
detail::all(tuple, f, std::make_index_sequence<sizeof...(T)>{});
}
}
This works very well in my scenarios, yet is obviously limited to static containers (like std::tuple). There is also a for-each-like iteration Meta::visit().
My question is: are there any other drawbacks / limitations with this approach?
Are there any improvements?

Related

Robust type caster for STL-vector-like classes

I have a class that is quite similar to an STL-vector (the differences are not important for the pybind11 type caster, so I will ignore them here). I have written a type caster for this class. A minimal working example of my code is given below. An example showing the problem is included below the code.
The problem is that my caster is quite limited (because I have used py::array_t). In principle the interface does accept tuples, lists, and numpy-arrays. However, when I overload based on typename, the interface fails for inputted tuples and lists (simply the first overload is selected even though it is the incorrect type).
My question is: How can I make the type caster more robust? Is there an effective way to re-use as much as possible existing type casters for STL-vector-like classes?
C++ code (including pybind11 interface)
#include <iostream>
#include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
// class definition
// ----------------
template<typename T>
class Vector
{
private:
std::vector<T> mData;
public:
Vector(){};
Vector(size_t N) { mData.resize(N); };
auto data () { return mData.data (); };
auto data () const { return mData.data (); };
auto begin() { return mData.begin(); };
auto begin() const { return mData.begin(); };
auto end () { return mData.end (); };
auto end () const { return mData.end (); };
size_t size () const { return mData.size (); };
std::vector<size_t> shape() const { return std::vector<size_t>(1, mData.size()); }
std::vector<size_t> strides() const { return std::vector<size_t>(1, sizeof(T) ); }
template<typename It> static Vector<T> Copy(It first, It last) {
Vector out(last-first);
std::copy(first, last, out.begin());
return out;
}
};
// C++ functions: overload based on type
// -------------------------------------
Vector<int> foo(const Vector<int> &A){ std::cout << "int" << std::endl; return A; }
Vector<double> foo(const Vector<double> &A){ std::cout << "double" << std::endl; return A; }
// pybind11 type caster
// --------------------
namespace pybind11 {
namespace detail {
template<typename T> struct type_caster<Vector<T>>
{
public:
PYBIND11_TYPE_CASTER(Vector<T>, _("Vector<T>"));
bool load(py::handle src, bool convert)
{
if ( !convert && !py::array_t<T>::check_(src) ) return false;
auto buf = py::array_t<T, py::array::c_style | py::array::forcecast>::ensure(src);
if ( !buf ) return false;
auto rank = buf.ndim();
if ( rank != 1 ) return false;
value = Vector<T>::Copy(buf.data(), buf.data()+buf.size());
return true;
}
static py::handle cast(const Vector<T>& src, py::return_value_policy policy, py::handle parent)
{
py::array a(std::move(src.shape()), std::move(src.strides()), src.data());
return a.release();
}
};
}} // namespace pybind11::detail
// Python interface
// ----------------
PYBIND11_MODULE(example,m)
{
m.doc() = "pybind11 example plugin";
m.def("foo", py::overload_cast<const Vector<int > &>(&foo));
m.def("foo", py::overload_cast<const Vector<double> &>(&foo));
}
Example
import numpy as np
import example
print(example.foo((1,2,3)))
print(example.foo((1.5,2.5,3.5)))
print(example.foo(np.array([1,2,3])))
print(example.foo(np.array([1.5,2.5,3.5])))
Output:
int
[1 2 3]
int
[1 2 3]
int
[1 2 3]
double
[1.5 2.5 3.5]
A very easy solution is to specialise pybind11::detail::list_caster. The type caster now becomes as easy as
namespace pybind11 {
namespace detail {
template <typename Type> struct type_caster<Vector<Type>> : list_caster<Vector<Type>, Type> { };
}} // namespace pybind11::detail
Note that this does require Vector to have the methods:
clear()
push_back(const Type &value)
reserve(size_t n) (seems optional in testing)
Complete example
#include <iostream>
#include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
// class definition
// ----------------
template<typename T>
class Vector
{
private:
std::vector<T> mData;
public:
Vector(){};
Vector(size_t N) { mData.resize(N); };
auto data () { return mData.data (); };
auto data () const { return mData.data (); };
auto begin() { return mData.begin(); };
auto begin() const { return mData.begin(); };
auto end () { return mData.end (); };
auto end () const { return mData.end (); };
size_t size () const { return mData.size (); };
void push_back(const T &value) { mData.push_back(value); }
void clear() { mData.clear(); }
void reserve(size_t n) { mData.reserve(n); }
std::vector<size_t> shape() const { return std::vector<size_t>(1, mData.size()); }
std::vector<size_t> strides() const { return std::vector<size_t>(1, sizeof(T) ); }
template<typename It> static Vector<T> Copy(It first, It last) {
printf("Vector<T>::Copy %s\n", __PRETTY_FUNCTION__);
Vector out(last-first);
std::copy(first, last, out.begin());
return out;
}
};
// C++ functions: overload based on type
// -------------------------------------
Vector<int> foo(const Vector<int> &A){ std::cout << "int" << std::endl; return A; }
Vector<double> foo(const Vector<double> &A){ std::cout << "double" << std::endl; return A; }
// pybind11 type caster
// --------------------
namespace pybind11 {
namespace detail {
template <typename Type> struct type_caster<Vector<Type>> : list_caster<Vector<Type>, Type> { };
}} // namespace pybind11::detail
// Python interface
// ----------------
PYBIND11_MODULE(example,m)
{
m.doc() = "pybind11 example plugin";
m.def("foo", py::overload_cast<const Vector<double> &>(&foo));
m.def("foo", py::overload_cast<const Vector<int > &>(&foo));
}

Creating class object c++ in if-statement

I actually have a small question. I want to create an attribute "function" which should be from the class function1, function2 or function3. Is there a way I can do that?
Here is the code:
double Uppersum::evalIntegral(double p_) {
if (functiontype == FUNKTION1){
Function1 function;
}
else if (functiontype == FUNKTION2) {
Function2 function;
}
else if (functiontype == FUNKTION3){
Function3 function;
}
function.setParameterP(p_);
double increment_h = (boundary_b - boundary_a)/num_subintervalls_m;
double sum = 0;
for (int index_i = 0; index_i < num_subintervalls_m -1; index_i++){
double x_1 = index_i * increment_h;
double x_2 = (index_i+1) * increment_h;
double y_1, y_2;
y_1 = function.evalFunctionValue(x_1);
y_2 = function.evalFunctionValue(x_2);
sum += increment_h * std::max(y_1, y_2);
}
}
class Function {
protected:
double parameter_p;
public:
void setParameterP(double p_);
virtual double evalFunctionValue(double x_)=0;
};
class Function1 : public Function {
public:
double evalFunctionValue(double x_);
};
Why not use inheritance, superclass has the virtual functions setParameterP and evalFunctionValue. and in subclasses, override those virtual functions.
here is the test code:
test.cpp
#include <iostream>
typedef enum{
FUNCTION1,
FUNCTION2,
FUNCTION3
}FunctionType;
using namespace std;
class super
{
public:
super(){}
~super(){}
virtual void setParameterP() = 0;
virtual void evalFunctionValue() = 0;
};
class func1:public super
{
public:
func1(){}
virtual void setParameterP(){cout<<"call setParameterP In func1"<<endl;}
virtual void evalFunctionValue(){cout<<"call evalFunctionValue In func1"<<endl;}
};
class func2:public super
{
public:
func2(){}
virtual void setParameterP(){cout<<"call setParameterP In func2"<<endl;}
virtual void evalFunctionValue(){cout<<"call evalFunctionValue In func2"<<endl;}
};
class func3:public super
{
public:
func3(){}
virtual void setParameterP(){cout<<"call setParameterP In func3"<<endl;}
virtual void evalFunctionValue(){cout<<"call evalFunctionValue In func3"<<endl;}
};
class FuncFactory
{
public:
static super* create(FunctionType var)
{
super* ret = nullptr;
switch (var)
{
case FUNCTION1:
ret = new func1();
break;
case FUNCTION2:
ret = new func2();
break;
case FUNCTION3:
ret = new func3();
break;
default:
cout <<"invalid FunctionType" << endl;
}
return ret;
}
};
int main(int argc, char** argv)
{
super* pFunc = FuncFactory::create(FUNCTION1);
pFunc->setParameterP();
pFunc->evalFunctionValue();
delete pFunc;
pFunc = FuncFactory::create(FUNCTION2);
pFunc->setParameterP();
pFunc->evalFunctionValue();
delete pFunc;
pFunc = FuncFactory::create(FUNCTION3);
pFunc->setParameterP();
pFunc->evalFunctionValue();
delete pFunc;
return 0;
}
here is the process result:
result

member function as callback

I would like to pass a member function of an instantiated object to another function. Example code is below. I am open for any strategy that works, including calling functional() from another function inside memberfuncpointertestclass using something like lambda or std::bind. Please note that I did not understand most of the threads I found with google about lambda or std::bind, so please, if possible, keep it simple. Also note that my cluster does not have C++ 11 and I would like to keep functional() as simple as it is. Thank you!
int functional( int (*testmem)(int arg) )
{
int a = 4;
int b = testmem(a);
return b;
}
class memberfuncpointertestclass
{
public:
int parm;
int member( int arg )
{
return(arg + parm);
}
};
void funcpointertest()
{
memberfuncpointertestclass a;
a.parm = 3;
int (*testf)(int) = &a.member;
std::cout << functional(testf);
}
int main()
{
funcpointertest();
return 0;
}
You cannot invoke a method on an object without an instance to refer to. So, you need to pass in both the instance as well as the method you want to invoke.
Try changing functional to:
template <typename T, typename M>
int functional(T *obj, M method)
{
int a = 4;
int b = (obj->*(method))(a);
return b;
}
And your funcpointertest to:
void funcpointertest()
{
memberfuncpointertestclass a;
a.parm = 3;
std::cout << functional(&a, &memberfuncpointertestclass::member);
}
This is a job for std::function, a polymorphic function wrapper. Pass to functional(...) such a function object:
#include <functional>
typedef std::tr1::function<int(int)> CallbackFunction;
int functional(CallbackFunction testmem)
{
int a = 4;
int b = testmem(a);
return b;
}
then use std::bind to create a function object of the same type that wraps memberfuncpointertestclass::method() of instance a:
void funcpointertest()
{
memberfuncpointertestclass a;
a.parm = 3;
CallbackFunction testf = std::bind(&memberfuncpointertestclass::member, &a, std::placeholders::_1);
std::cout << functional(testf);
}
Check this item for more details.

Fibonacci Sequence error

I am coding a Fibonacci sequence in Eclipse and this is my code-
public class FibonacciAlgorithm {
private int a = 0;
private int b = 1;
public FibonacciAlgorithm() {
}
public int increment() {
int temp = b;
b = a + b;
a = temp;
return value;
}
public int getValue() {
return b;
}
}
It is showing an error in the return value; line saying value cannot be resolved to a variable. I don't see any other errors.
Where is value defined? You return something that was not defined anywhere.
You don't have a "value" defined, this is your error. I don't remember the thing exactly, but I think you don't need a and b, I found this in my code archive, hope it helps.
public class Fibonacci
{
public static long fibo(int n)
{
if (n <= 1) return n;
else return fibo(n - 1) + fibo(n - 2);
}
public static void main() {
int count = 5; // change accordingly, bind to input etc.
int N = Integer.parseInt(count);
for (int i = 1; i <= N; i++)
System.out.println(i + ": " + fibo(i));
}
}
In case you want to stay with your own code, try returning "b" as value.
Your method is returning an int variable so you would have to define and return value as an int
I am not sure what you trying to do.
If you have "getValue" method I think "increment" method should be void.
When you want current Fibonacci value use "getValue" method.
public class FibonacciAlgorithm {
private int a = 0;
private int b = 1;
public FibonacciAlgorithm() {
}
public void increment() {
int temp = b;
b = a + b;
a = temp;
}
public int getValue() {
return b;
}

Why does this keep giving errors?

I'm trying to code some stuff for a game but I keep getting error messages on 8 lines that keep saying "Expected '=', ',', ';', 'asm' or 'attribute' before "insert what it's talking about here""
Its annoying and I can't figure out why. Here is the code:
class Vec2 **"error here before Vec2"**
{
public:
float X, Y;
Vec2() {}
Vec2(const float &x, const float &y) :
X(x),
Y(y)
{
};
float &operator[] (const int &index)
{
switch (index)
{
case 0:
return X;
case 1:
return Y;
}
throw Exceptions::IndexOutOfRange();
};
float *operator & ()
{
return &X;
};
};
template<> class TypeInfo<Vec2> : public TypeInfo_Atomic<Vec2> {}; **"error here before <"**
class Vec3 **"error here before Vec3"**
{
public:
float X, Y, Z;
Vec3() {}
Vec3(const float &x, const float &y, const float &z) :
X(x),
Y(y),
Z(z)
{
};
float &operator[] (const int &index)
{
switch (index)
{
case 0:
return X;
case 1:
return Y;
case 2:
return Z;
}
throw Exceptions::IndexOutOfRange();
};
float *operator & ()
{
return &X;
};
};
template<> class TypeInfo<Vec3> : public TypeInfo_Atomic<Vec3> {}; **"error here before <"**
class Vec4 **"error here before Vec4"**
{
public:
float X, Y, Z, W;
Vec4() {}
Vec4(const float &x, const float &y, const float &z, const float &w) :
X(x),
Y(y),
Z(z),
W(w)
{
};
float &operator[] (const int &index)
{
switch (index)
{
case 0:
return X;
case 1:
return Y;
case 2:
return Z;
case 3:
return W;
}
throw Exceptions::IndexOutOfRange();
};
float *operator & ()
{
return &X;
};
};
template<> class TypeInfo<Vec4> : public TypeInfo_Atomic<Vec4> {}; **"error here before <"**
class Color **"error here before Color"**
{
public:
byte R, G, B, A;
Color() {}
Color(byte r, byte g, byte b, byte a) :
R(r),
G(g),
B(b),
A(a)
{
};
byte *operator & ()
{
return &R;
};
static const Color Red,
Green,
Blue,
Yellow,
White,
Black;
};
template<> class TypeInfo<Color> : public TypeInfo_Atomic<Color> {}; **"flag here before <"**
there are 8 errors total. Help would be hugely appreciated!
If you're putting objective-c and c++ code into the same file, you need to use a .mm file extension.
http://developer.apple.com/library/ios/#referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/_index.html
It doesn't think your module is C++. What suffix did you give the file?