Wrapping a template function with boost.python - c++

I'm trying to expose the following c++ function to python using boost.python:
template <typename genType>
genType refract(
genType const & I,
genType const & N,
typename genType::value_type const & eta);
and what I got is this:
template<typename N>
N reflect(N const & i, N const & n, typename N::value_type const & eta)
{
return glm::N refract(i,n,eta);
}
BOOST_PYTHON_MODULE(foo)
{
def("reflect", reflect<float>);
def("reflect", reflect<double>);
}
and I have the following error when compiling:
error C2780: 'void boost::python::def(const char *,F,const A1 &,const A2 &,const A3 &)' : expects 5 arguments - 2 provided
How should I wrap it?
-----edit------
This works:
template<class T>
T floor(T x)
{
return glm::core::function::common::floor(x);
}
BOOST_PYTHON_MODULE(busta)
{
def("floor", floor<double>);
def("floor", floor<float>);
}
from the reference, floor() definition is the folowing:
template< typename genType >
genType floor (genType const &x)
I can build this as a DLL, then import it in python and use floor() from there. Life feels so nice...but..
This won't work, and I would like to understand why:
template<class genType >
genType reflect (genType i, genType n, genType eta)
{
return glm::core::function::geometric::refract(i, n,eta);
}
BOOST_PYTHON_MODULE(busta)
{
def("reflect", reflect<float>);
}
refract() definition is on the top of this post.
the error I get now is this:
1>foo.cpp(37): error C2893: Failed to specialize function template 'genType glm::core::function::geometric::refract(const genType &,const genType &,const genType::value_type &)'
1> With the following template arguments:
1> 'float'
1> foo.cpp(60) : see reference to function template instantiation 'genType
`anonymous-namespace'::reflect<float>(genType,genType,genType)' being compiled
1> with
1> [
1> genType=float
1> ]
1>
1>Build FAILED.

This is not the perfect answer since it requires abusing the type system and writing plenty of additional glue code.
You could try defining a wrapper template to decorate your target type such that it would have the necessary typedefs to satisfy the calling function (reflect).
This example demonstrates the failings of such an approach. Notice that this reflect function performs a simple addition; however, for C++ to recognize the operator+ for the templated type N, the wrapper must explicitly define it.
#include <iostream>
using namespace std;
template<class N>
N reflect(const N& n, const typename N::value_type& t)
{
return n + t;
}
template<class N>
struct wrapper
{
typedef N value_type;
wrapper(const N& n):_n(n){}
operator N& () { return _n; }
N operator+ (const N& r) const { return _n + r; }
N _n;
};
int main(int,char**)
{
cout << reflect( wrapper<double>(1), 2.0) << endl;
return 0;
}

Related

Export container class with LuaBridge

I want to export SRect and SRectVector from C++ to Lua, but compile fails.
What is the proper way to do it?
Compiler: vs2019, vc++11
OS: Win10 64
Push() meets compile error,
I think the argument is just SRectVector *, why the compiler thinks it is 'std::vector<SRect,std::allocator<_Ty>>'?
class SRect{
public:
int left;
int top;
int right;
int bottom;
SRect(int l, int t, int r, int b)
: left(l)
, top(t)
, right(r)
, bottom(b){}
//...
};
typedef std::vector<SRect> SRectVector;
luabridge::getGlobalNamespace(L)
.beginClass <SRect>("SRect")
.addConstructor <void(*) (int, int, int, int)>()
.addProperty("left", &SRect::left)
//...
.endClass()
.beginClass <SRectVector>("SRectVector")
.addFunction("Push",
std::function <void(SRectVector*, const SRect&)>(
[](SRectVector* vec, const SRect& rc) { (*vec).push_back(rc); }))
//...
.endClass()
.endNamespace();
```
1>E:\Code\include\LuaBridge/detail/TypeList.h(177): error C2664: 'luabridge::detail::TypeListValues<luabridge::detail::TypeList<Param,luabridge::detail::TypeList<const SRect&,luabridge::detail::MakeTypeList<>::Result>>>::TypeListValues(luabridge::detail::TypeListValues<luabridge::detail::TypeList<Param,luabridge::detail::TypeList<const SRect&,luabridge::detail::MakeTypeList<>::Result>>> &&)': cannot convert argument 1 from 'std::vector<SRect,std::allocator<_Ty>>' to 'Head'
1> with
1> [
1> Param=SRectVector *
1> ]
1> and
1> [
1> _Ty=SRect
1> ]
1> and
1> [
1> Head=SRectVector *
1> ]
1>E:\Code\include\LuaBridge/detail/TypeList.h(179): note: No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1>E:\Code\include\LuaBridge/detail/TypeList.h(176): note: while compiling class template member function 'luabridge::detail::ArgList<Params,1>::ArgList(lua_State *)'
After more digging, I found the reason. A completed user defined class can be easily exported. But a container pointer not. Compiles OK after I added such code,
namespace LuaBridge
{
template <>
struct Stack <SRectVector*>
{
static void push(lua_State* L, SRectVector* ptr)
{
SRectVector** pp = (SRectVector**)lua_newuserdata(L, sizeof(SRectVector*));
*pp = ptr;
}
static SRectVector* get(lua_State* L, int index)
{
return (SRectVector*)lua_touserdata(L, index);
}
};
}
Or add a more generic one,
template <class T>
struct Stack <std::vector<T>*>
{
typedef typename std::vector<T>* ContainerPointerType;
static void push(lua_State* L, ContainerPointerType ptr)
{
ContainerPointerType* pp = (ContainerPointerType*)lua_newuserdata(L, sizeof(ContainerPointerType));
*pp = ptr;
}
static ContainerPointerType get(lua_State* L, int index)
{
return (ContainerPointerType)lua_touserdata(L, index);
}
};
Do not include <LuaBridge/Vector.h>, then solve this issue.

Visitor variant with multiple types (string, bool, integral, float)

I'm trying to use a variant's visitor for multiple types and then generating a new random value. Be aware that I can't use more recent compiler than Visual Studio 2015 Update 3 and GCC 4.9 because of reasons out of my control.
Here is what I have
std::random_device randomDevice;
std::mt19937 randomEngine(randomDevice());
typedef mpark::variant< // Implementation of std::variant for C++11,14
bool,
int8_t, uint8_t,
int16_t, uint16_t,
int32_t, uint32_t,
int64_t, uint64_t,
float, double,
std::string
> VariantValue;
struct ValueVisitor
{
ValueVisitor(VariantValue* pNewVal)
: pNewVal(pNewVal) {}
void operator()(const std::string & s) const
{
// Generate some random string into *pNewVal
}
void operator()(const bool& t) const
{
*pNewVal = !t;
}
template <typename T,
std::enable_if_t<std::is_integral<T>::value>* = nullptr,
std::enable_if_t<!std::is_same<T, bool>::value>* = nullptr>
>
void operator()(const T& t) const
{
std::uniform_int_distribution<T> dist
(
std::numeric_limits<T>::lowest(),
std::numeric_limits<T>::max()
);
*pNewVal = dist(randomEngine);
}
template <typename T, typename std::enable_if<
std::is_floating_point<T>::value>::type* = nullptr>
void operator()(const T& t) const
{
std::uniform_real_distribution<T> dist
(
std::numeric_limits<T>::lowest(),
std::numeric_limits<T>::max()
);
*pNewVal = dist(randomEngine);
}
VariantValue* pNewVal;
};
VariantValue vSource {(double)12 };
VariantValue vTarget;
ValueVisitor valueVisitor(&vTarget);
mpark::visite(valueVisitor, v);
But I'm getting the error C2338 invalid template argument for uniform_int_distribution.
Looking at output window for more details
1>c:\program files (x86)\microsoft visual studio 14.0\vc\include\random(2387): error C2338: invalid template argument for uniform_int_distribution
1> d:\project\xxx.cpp(271): note: see reference to class template instantiation 'std::uniform_int_distribution<T>' being compiled
1> with
1> [
1> T=int8_t
1> ]
1> d:\project\3rdparty\mpark\include\mpark\lib.hpp(237): note: see reference to function template instantiation 'void ValueVisitor::operator ()<T,void>(const T &) const' being compiled
1> with
1> [
1> T=int8_t
1> ]
...
So, If I well understood, it seems that when T=bool the functor's function targeted is the one for is_integral. But why ? I explicitly removed the bool type with std::enable_if_t<!std::is_same<T, bool>::value>* = nullptr.
I tried a different approaches like
template <typename T>
void operator()(const T & t)
{
if (std::is_same<T, bool>::value) {
} else if (std::is_floating_point<T>::value) {
} else if (std::is_integral<T>::value) {
} else if (std::is_same<T, std::string>::value) {
}
But without success, it's worst as now the float variation are still trying to use the uniform_int_distribution.
I'm really out of idea.
Best regards,

Error while compiling in visual c++

I have compiled the below code :
typedef unsigned char uint8;
template <uint8 N> inline uint8 g(uint8 x) { return x > N ? 1 : 0; }
template <size_t stride, size_t boxsize, class T, class F>
inline void boxfilt(size_t width, size_t size, T * inout, const F & f) {
}
template <class T> inline T self(const T & x) { return x; }
template <size_t stride, size_t boxsize, class T>
inline void boxfilt(size_t width, size_t size, T * inout) {
return boxfilt<stride, boxsize>(width, size, inout, self<T>);
}
int main(int argc, char* argv[])
{
uint8 *out = NULL;
boxfilt<3,4>(10,29,out,g<4>);
return 0;
}
In g++ compiler, it works fine. When I try to compile the same code in Visual Studio 2008 compiler, it shows the following error:
Error 1 error C2780: 'void boxfilt(size_t,size_t,T *)' : expects 3 arguments - 4 provided g:\testfjx\test\test.cpp
Error 2 error C2784: 'void boxfilt(size_t,size_t,T *,const F &)' : could not deduce template argument for 'overloaded function type' from 'overloaded function type' g:\testfjx\test\test.cpp
Error 3 error C2784: 'void boxfilt(size_t,size_t,T *,const F &)' : could not deduce template argument for 'T *' from 'uint8 *' g:\testfjx\test\test.cpp
How can I resolve this problem?
It is OK, in Visual C++ 2008 too.
If both VC++2008 and G++4.7.2 accept the code and VC++2005 doesn't, so maybe VC++2005 has bug, maybe it doesn't implement C++ specification completely.

weird compiler error using bind2nd(): "member function already defined or declared" instead of "reference to reference"

I recently spent quite some time understanding the error message when calling func() in this piece of code:
int main()
{
vector< vector<double> > v;
double sum = 0;
for_each( v.begin(), v.end(),
bind2nd( ptr_fun(func), &sum ) );
return 0;
}
when func() was declared like so, the code compiled fine:
void func( vector<double> v, double *sum )
{
}
when I used this declaration (for efficiency), I got a compiler error:
void func( const vector<double> &v, double *sum )
{
}
The error I expected to see was something like a reference-to-reference error, because of the definition of operator() of binder2nd,
result_type operator()(const argument_type& _Left) const
Instead, to my surprise, the error the Visual C++ (VS2012) compiler gave me was:
error C2535: 'void std::binder2nd<_Fn2>::operator ()(const
std::vector<_Ty> &) const' : member function already defined or
declared
which I cannot decipher.
Can you explain under which mechanism the operator() is already
defined?
The full error I got was:
error C2535: 'void std::binder2nd<_Fn2>::operator ()(const std::vector<_Ty> &) const' : member function already defined or declared
with
[
_Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>,
_Ty=double
]
c:\vc\include\xfunctional(319) : see declaration of 'std::binder2nd<_Fn2>::operator ()'
with
[
_Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>
]
c:\consoleapplication1.cpp(31) : see reference to class template instantiation 'std::binder2nd<_Fn2>' being compiled
with
[
_Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>
]
Build FAILED.
This behavior is well-defined (every correct C++ compiler will fail to compile your code).
From the standard (N3376) section D.9.3 on class template binder2nd, these two defintions of operator() exist:
typename Fn::result_type
operator()(const typename Fn::first_argument_type& x) const;
typename Fn::result_type
operator()(typename Fn::first_argument_type& x) const;
If first_argument_type is already a const T&, then they will be conflicting.
This isn't an answer, but I just want to record the modern C++11 solution, where all the small bind helpers are deprecated in favour of the universal std::bind:
#include <functional>
#include <vector>
#include <algorithm>
void func(std::vector<double> const & v, double * sum) { /* ... */ }
int main()
{
std::vector<std::vector<double>> v;
double sum = 0;
std::for_each(v.begin(), v.end(), std::bind(func, std::placeholders::_1, &sum));
}
The variadic templates of C++11, as well as a more comprehensive collection of type-modifying traits, give std::bind much stronger deduction abilities than the previous components in <functional>.

How to expose boost::tuples::tuple to Java bindings?

I have a list of boost::tuple. I want to expose this tuple list to Java bindings through SWIG. But when I try to compile mt wrap.cxx, generated by SWIG, I get following errors:
d:\xyz\...\vector.h(115) : error C2678: binary '==' : no operator found which takes a left-hand operand of type 'const boost::tuples::tuple<T0,T1>' (or there is no acceptable conversion)
with
[
T0=std::string,
T1=std::string
]
c:\program files\microsoft visual studio 8\vc\platformsdk\include\guiddef.h(192): or 'int operator ==(const GUID &,const GUID &)'
while trying to match the argument list '(const boost::tuples::tuple<T0,T1>, const MyTuple)'
with
[
T0=std::string,
T1=std::string
]
d:\xyz\...\vector.h(111) : while compiling class template member function 'int Vector<T>::index(const T &) const'
with
[
T=MyTuple
]
d:\xyz\...\MyTuple_wrap.cxx(17731) : see reference to class template instantiation 'Vector<T>' being compiled
with
[
T=MyTuple
]
Can anyone tell me what I should do to resolve this issue?
It is unclear how you arrived at the error you've shown. boost::tuple is tricky to wrap by default and there doesn't seem to be any standard interface to it included with SWIG. In my tests I couldn't get close to the error you were seeing without manually writing an interface file.
I did however succeeded in wrapping boost's tuples using the following interface file:
%{
#include <boost/tuple/tuple.hpp>
%}
namespace boost {
template <typename T1=void, typename T2=void, typename T3=void>
struct tuple;
template <>
struct tuple<void,void,void> {
};
template <typename T1>
struct tuple<T1, void, void> {
tuple(T1);
%extend {
T1 first() const {
return boost::get<0>(*$self);
}
}
};
template <typename T1, typename T2>
struct tuple <T1, T2, void> {
tuple(T1,T2);
%extend {
T1 first() const {
return boost::get<0>(*$self);
}
T2 second() const {
return boost::get<1>(*$self);
}
}
};
template <typename T1, typename T2, typename T3>
struct tuple <T1,T2,T3> {
tuple(T1,T2,T3);
%extend {
T1 first() const {
return boost::get<0>(*$self);
}
T2 second() const {
return boost::get<1>(*$self);
}
T3 third() const {
return boost::get<2>(*$self);
}
}
};
}
Basically all it does is add accessor functions to each of the specialisations of tuple you might care about. It's sufficient to make it minimally useful in Java or some other language. You would want to expand on this to cover larger tuples. You probably want to make the member functions get/set if your tuples aren't intended to be immutable.
I was able to test this with a SWIG module:
%module test
%include "boost_tuple.i"
%template(TestTuple) boost::tuple<int, double, char>;
%template(SingleTuple) boost::tuple<char>;
%inline %{
boost::tuple<int, double, char> func1() {
return boost::make_tuple(3, 2.0, '1');
}
void test1(boost::tuple<int, double, char>) {
}
%}
Which worked as expected with the following Java:
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
TestTuple t = test.func1();
System.out.println("1: " + t.first() + " 2: " + t.second() + " 3: " + t.third());
test.test1(test.func1());
test.test1(new TestTuple(0, 0.0, '0'));
}
}