How to expose boost::tuples::tuple to Java bindings? - c++

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'));
}
}

Related

what is the way to remove the first element from a std::span<T>?

when reading the document of std::span, I see there is no method to remove the first element from the std::span<T>.
Can you suggest a way to solve my issue?
The large picture of my problem(I asked in another question: How to instantiatiate a std::basic_string_view with custom class T, I got is_trivial_v<_CharT> assert error) is that I would like to have a std::basic_string_view<Token>, while the Token is not a trivial class, so I can't use std::basic_string_view, and someone suggested me to use std::span<Token> instead.
Since the basic_string_view has a method named remove_prefix which remove the first element, while I also need such kinds of function because I would like to use std::span<Token> as a parser input, so the Tokens will be matched, and consumed one by one.
Thanks.
EDIT 2023-02-04
I try to derive a class named Span from std::span, and add the remove_prefix member function, but it looks like I still have build issues:
#include <string_view>
#include <vector>
#include <span>
// derived class, add remove_prefix function to std::span
template<typename T>
class Span : public std::span<T>
{
public:
// Inheriting constructors
using std::span<T>::span;
// add a public function which is similar to std::string_view::remove_prefix
constexpr void remove_prefix(std::size_t n) {
*this = subspan(n);
}
};
struct Token
{
Token(){};
Token(const Token& other)
{
lexeme = other.lexeme;
type = other.type;
}
std::string_view lexeme;
int type;
// equal operator
bool operator==(const Token& other)const {
return (this->lexeme == other.lexeme) ;
}
};
template <typename T>
struct Viewer;
template <>
struct Viewer<Token>
{
using type = Span<Token>; // std::span or derived class
};
template <>
struct Viewer<char>
{
using type = std::string_view;
};
template <typename T> using ViewerT = typename Viewer<T>::type;
template <typename T>
class Parser
{
using v = ViewerT<T>;
};
// a simple parser demo
template <typename Base, typename T>
struct parser_base {
using v = ViewerT<T>;
constexpr auto operator[](v& output) const noexcept;
};
template<typename T>
struct char_ final : public parser_base<char_<T>, T> {
using v = ViewerT<T>;
constexpr explicit char_(const T ch) noexcept
: ch(ch)
{}
constexpr inline bool visit(v& sv) const& noexcept {
if (!sv.empty() && sv.front() == ch) {
sv.remove_prefix(1);
return true;
}
return false;
}
private:
T ch;
};
template <typename Parser, typename T>
constexpr bool parse(Span<T> &input, Parser const& parser) noexcept {
return parser.visit(input);
}
int main()
{
Token kw_class;
kw_class.lexeme = "a";
std::vector<Token> token_stream;
token_stream.push_back(kw_class);
token_stream.push_back(kw_class);
token_stream.push_back(kw_class);
Span<Token> token_stream_view{&token_stream[0], 3};
auto p = char_(kw_class);
parse(token_stream_view, p);
return 0;
}
The build error looks like below:
[ 50.0%] g++.exe -Wall -std=c++20 -fexceptions -g -c F:\code\test_crtp_twoargs\main.cpp -o obj\Debug\main.o
F:\code\test_crtp_twoargs\main.cpp: In member function 'constexpr void Span<T>::remove_prefix(std::size_t)':
F:\code\test_crtp_twoargs\main.cpp:52:17: error: there are no arguments to 'subspan' that depend on a template parameter, so a declaration of 'subspan' must be available [-fpermissive]
52 | *this = subspan(n);
| ^~~~~~~
F:\code\test_crtp_twoargs\main.cpp:52:17: note: (if you use '-fpermissive', G++ will accept your code, but allowing the use of an undeclared name is deprecated)
F:\code\test_crtp_twoargs\main.cpp: In instantiation of 'constexpr void Span<T>::remove_prefix(std::size_t) [with T = Token; std::size_t = long long unsigned int]':
F:\code\test_crtp_twoargs\main.cpp:113:29: required from 'constexpr bool char_<T>::visit(v&) const & [with T = Token; v = Span<Token>]'
F:\code\test_crtp_twoargs\main.cpp:125:24: required from 'constexpr bool parse(Span<T>&, const Parser&) [with Parser = char_<Token>; T = Token]'
F:\code\test_crtp_twoargs\main.cpp:141:10: required from here
F:\code\test_crtp_twoargs\main.cpp:52:24: error: 'subspan' was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive]
52 | *this = subspan(n);
| ~~~~~~~^~~
F:\code\test_crtp_twoargs\main.cpp:52:24: note: declarations in dependent base 'std::span<Token, 18446744073709551615>' are not found by unqualified lookup
F:\code\test_crtp_twoargs\main.cpp:52:24: note: use 'this->subspan' instead
F:\code\test_crtp_twoargs\main.cpp:52:15: error: no match for 'operator=' (operand types are 'Span<Token>' and 'std::span<Token, 18446744073709551615>')
52 | *this = subspan(n);
| ~~~~~~^~~~~~~~~~~~
F:\code\test_crtp_twoargs\main.cpp:44:7: note: candidate: 'constexpr Span<Token>& Span<Token>::operator=(const Span<Token>&)'
44 | class Span : public std::span<T>
| ^~~~
F:\code\test_crtp_twoargs\main.cpp:44:7: note: no known conversion for argument 1 from 'std::span<Token, 18446744073709551615>' to 'const Span<Token>&'
F:\code\test_crtp_twoargs\main.cpp:44:7: note: candidate: 'constexpr Span<Token>& Span<Token>::operator=(Span<Token>&&)'
F:\code\test_crtp_twoargs\main.cpp:44:7: note: no known conversion for argument 1 from 'std::span<Token, 18446744073709551615>' to 'Span<Token>&&'
Any idea on how to fix this issue?
Also, I don't know how to make a general parse function:
template <typename Parser, typename T>
constexpr bool parse(Span<T> &input, Parser const& parser) noexcept {
return parser.visit(input);
}
Currently, the first argument of the parse should be a Viewer like type?
EDIT2023-02-05
Change the function as below, the above code can build correctly. This is from Benjamin Buch's answer.
constexpr void remove_prefix(std::size_t n) {
auto& self = static_cast<std::span<T>&>(*this);
self = self.subspan(n);
}
There is still one thing remains: How to generalize the parse function to accept both input types of std::string_view and Span<Token>?
If I change the parse function to this:
template <typename Parser, typename T>
constexpr bool parse(ViewerT<T> &input, Parser const& parser) noexcept {
return parser.visit(input);
}
I got such compile error:
[ 50.0%] g++.exe -Wall -std=c++20 -fexceptions -g -c F:\code\test_crtp_twoargs\main.cpp -o obj\Debug\main.o
F:\code\test_crtp_twoargs\main.cpp: In function 'int main()':
F:\code\test_crtp_twoargs\main.cpp:143:24: error: no matching function for call to 'parse(Span<Token>&, char_<Token>&)'
143 | bool result = parse(token_stream_view, p);
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~
F:\code\test_crtp_twoargs\main.cpp:125:16: note: candidate: 'template<class Parser, class T> constexpr bool parse(ViewerT<T>&, const Parser&)'
125 | constexpr bool parse(ViewerT<T> &input, Parser const& parser) noexcept {
| ^~~~~
F:\code\test_crtp_twoargs\main.cpp:125:16: note: template argument deduction/substitution failed:
F:\code\test_crtp_twoargs\main.cpp:143:24: note: couldn't deduce template parameter 'T'
143 | bool result = parse(token_stream_view, p);
| ~~~~~^~~~~~~~~~~~~~~~~~~~~~
Any ideas?
Thanks.
BTW: I have to explicitly instantiation of the parse function call like:
bool result = parse<decltype(p), Token>(token_stream_view, p);
to workaround this issue.
Call subspan with 1 as only (template) argument to get a new span, which doesn't contain the first element.
If you use a span with a static extend, you need a new variable because the data type changes by subspan.
#include <string_view>
#include <iostream>
#include <span>
int main() {
std::span<char const, 12> text_a("a test-span");
std::cout << std::string_view(text_a) << '\n';
std::span<char const, 10> text_b = text_a.subspan<2>();
std::cout << std::string_view(text_b) << '\n';
}
If you have a dynamic extend, you can assign the result to the original variable.
#include <string_view>
#include <iostream>
#include <span>
int main() {
std::span<char const> text("a test-span");
std::cout << std::string_view(text) << '\n';
text = text.subspan(2);
std::cout << std::string_view(text) << '\n';
}
The implementation of a modifying inplace subspan version is only possible for spans with a dynamic extend. It can be implemented as a free function.
#include <string_view>
#include <iostream>
#include <span>
template <typename T>
constexpr void remove_front(std::span<T>& self, std::size_t const n) noexcept {
self = self.subspan(n);
}
int main() {
std::span<char const> text("a test-span");
std::cout << std::string_view(text) << '\n';
remove_front(text, 2);
std::cout << std::string_view(text) << '\n';
}
You can use your own spans derived from std::span if you prefer the dot-call.
#include <string_view>
#include <iostream>
#include <span>
template <typename T>
struct my_span: std::span<T> {
using std::span<T>::span;
constexpr void remove_front(std::size_t const n) noexcept {
auto& self = static_cast<std::span<T>&>(*this);
self = self.subspan(n);
}
};
int main() {
my_span<char const> my_text("a test-span");
std::cout << std::string_view(my_text) << '\n';
my_text.remove_front(2);
std::cout << std::string_view(my_text) << '\n';
}
You can also write a wrapper class to call via dot syntax. This way you can additionally implement cascadable modification calls by always returning the a reference modifier class.
#include <string_view>
#include <iostream>
#include <span>
template <typename T>
class span_modifier {
public:
constexpr span_modifier(std::span<T>& span) noexcept: span_(span) {}
constexpr span_modifier& remove_front(std::size_t const n) noexcept {
span_ = span_.subspan(n);
return *this;
}
private:
std::span<T>& span_;
};
template <typename T>
constexpr span_modifier<T> modify(std::span<T>& span) noexcept {
return span;
}
int main() {
std::span<char const> text("a test-span");
std::cout << std::string_view(text) << '\n';
modify(text).remove_front(2).remove_front(5);
std::cout << std::string_view(text) << '\n';
}
Note I use the template function modify to create an object of the wrapper class, because the names of classes cannot be overloaded. Therefore class names should always be a bit more specific. The function modify can also be overloaded for other data types, which then return a different wrapper class. This results in a simple intuitive and consistent interface for modification wrappers.
You can write remove_prefix of your version,
template <typename T>
constexpr void remove_prefix(std::span<T>& sp, std::size_t n) {
sp = sp.subspan(n);
}
Demo

How to initialize static array from std::integer_sequence?

I made an iterable generator for enums that conform with the following rules:
Enum is an integer sequence, there are no gaps
Given last element of the enum is not an actual enum element
The class looks like this:
template <typename EnumType, EnumType LENGTH>
class EnumArrayNonStatic
{
public:
using ValueType = typename std::underlying_type<EnumType>::type;
//! Initialize values via private constructor
constexpr EnumArrayNonStatic() : EnumArrayNonStatic(std::make_integer_sequence<ValueType, (ValueType)LENGTH>{}) {}
//! All values generated via std::integer_sequence
EnumType values[(int)LENGTH];
private:
//! Private constructor that populates values
template <int... Indices>
constexpr EnumArrayNonStatic(std::integer_sequence<int, Indices...>) : values{(static_cast<EnumType>(Indices))...} {}
};
Usage:
enum class TestEnum
{
A,
B,
C,
D,
LENGTH
};
int main()
{
for (const TestEnum val : EnumArrayNonStatic<TestEnum, TestEnum::LENGTH>().values)
{
std::cout << (int)val << "\n";
}
return 0;
}
However, I would instead like to be able to use EnumArray<TestEnum, TestEnum::LENGTH>::values and have the values generated via template during compilation. I wrote this:
template <typename EnumType, EnumType LENGTH>
class EnumArray
{
private:
using ValueType = typename std::underlying_type<EnumType>::type;
//! Static generator of value array (returns EnumType[])
template <ValueType... Indices>
static constexpr auto GenerateArray(std::integer_sequence<ValueType, Indices...>) { return {(static_cast<EnumType>(Indices))...}; }
public:
//! Static array of values of an enum
static constexpr EnumType values[static_cast<ValueType>(LENGTH)] = GenerateArray(std::make_integer_sequence<ValueType, static_cast<ValueType>(LENGTH) >{});
};
I've been messing around with the code for a while but I always keep getting errors. The version above prints:
1>enumiteratortest.cpp(22): error C3108: cannot deduce a type as an initializer list is not an expression
1>enumiteratortest.cpp(25): note: see reference to function template instantiation 'auto EnumArray<TestEnum,TestEnum::LENGTH>::GenerateArray<0,1,2,3>(std::integer_sequence<int,0,1,2,3>)' being compiled
1>enumiteratortest.cpp(52): note: see reference to class template instantiation 'EnumArray<TestEnum,TestEnum::LENGTH>' being compiled
1>enumiteratortest.cpp(22): error C2440: 'return': cannot convert from 'initializer list' to 'auto'
1>enumiteratortest.cpp(22): note: There is no context in which this conversion is possible
1>enumiteratortest.cpp(25): error C2440: 'initializing': cannot convert from 'void' to 'const EnumType [4]'
1> with
1> [
1> EnumType=TestEnum
1> ]
1>enumiteratortest.cpp(25): note: There are no conversions to array types, although there are conversions to references or pointers to arrays
Surely there must be a way to initialize the array statically. Is the GenerateArray even necessary? Isn't there a way to do this?
int myArray[] = std::integer_sequence<ValueType, Indices...>{Indices...}
Or something along the lines?
You cannot initialize a language array with an initializer_list. And, you cannot change the return type of that function to an array - functions cannot return arrays.
Just change everything to std::array:
template <ValueType... Indices>
static constexpr auto GenerateArray(std::integer_sequence<ValueType, Indices...>)
-> std::array<EnumType, sizeof...(Indices)>
{
return {(static_cast<EnumType>(Indices))...};
}
static constexpr std::array<EnumType, static_cast<ValueType>(LENGTH)> values
= GenerateArray(std::make_integer_sequence<ValueType, static_cast<ValueType>(LENGTH)>{});

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 in VS2013 when attempting to partially specialize a class template with another class template

Given the following class and function templates:
template <typename WrappedType, ParameterType ParamType, bool IsOutputParameter>
class WrappedParameter; // Definition left out for brevity
template <typename T>
struct ParameterUnwrapper
{
static T UnwrapParameter(const T& in_param)
{
return in_param;
}
};
template <typename T, ParameterType ParamType, bool IsOutputParameter>
struct ParameterUnwrapper<WrappedParameter<T, ParamType, IsOutputParameter>>
{
static T UnwrapParameter(const WrappedParameter<T, ParamType, IsOutputParameter>& in_param)
{
return in_param.GetWrapped();
}
};
template <typename T>
T UnwrapParameter(T in_param)
{
return Impl::ParameterUnwrapper<T>::UnwrapParameter(in_param);
}
template <typename T>
Impl::WrappedParameter<T, Impl::POINTER_PARAMETER, true> WrapOutputPointerParameter(T in_param)
{
return Impl::WrappedParameter<T, Impl::POINTER_PARAMETER, true>(in_param);
}
template <typename MemFunc, typename ...Args>
HRESULT ExecuteAndLog(
MemFunc in_memberFunction,
const std::string& in_methodName,
Args... args) //-> decltype((m_wrapped->*in_memberFunction)(UnwrapParameter(args)...))
{
return ExecuteFunctorAndLog(
[&]() { return (m_wrapped->*in_memberFunction)(UnwrapParameter(args)...); },
in_methodName,
args...);
}
The following call: (The ExecuteAndLog)
HRESULT STDMETHODCALLTYPE AccessorWrapper::AddRefAccessor(
HACCESSOR hAccessor,
DBREFCOUNT *pcRefCount)
{
return ExecuteAndLog(
&IAccessor::AddRefAccessor,
"AddRefAccessor",
hAccessor,
WrapOutputPointerParameter(pcRefCount));
}
Gives me errors:
error C2664: 'HRESULT (HACCESSOR,DBREFCOUNT *)' : cannot convert argument 2 from 'Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>' to 'DBREFCOUNT *'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
see reference to function template instantiation 'ExecuteAndLog<HRESULT(__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *),HACCESSOR, Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>>(MemFunc,const std::string &,HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>)' being compiled
with
[
MemFunc=HRESULT (__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *)
]
see reference to function template instantiation 'ExecuteAndLog<HRESULT(__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *),HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>>(MemFunc,const std::string &,HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>)' being compiled
with
[
MemFunc=HRESULT (__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *)
]
I think I've messed up the partial specialization of ParameterUnwrapper (or my approach is just wrong). Any advice?
More information:
Impl is a nested namespace (alongside the namespace all the provided templates except ExecuteAndLog are in)
m_wrapped is of type IAccessor* (the COM interface) in this case.
enum ParameterType
{
POINTER_PARAMETER,
ARRAY_PARAMETER
};
UPDATE:
Here's a self contained example: http://codepad.org/lwTzVImb
The error I get in VS2013 for this one is:
error C2664: 'int (int,int **,size_t *)' : cannot convert argument 2 from 'WrappedParameter<int **,ARRAY_PARAMETER,true>' to 'int **'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
see reference to function template instantiation 'int ExecuteAndLog<int(__thiscall A::* )(int,int **,size_t *),int,WrappedParameter<int **,ARRAY_PARAMETER,true>,size_t*>(MemFunc,const std::string &,int,WrappedParameter<int **,ARRAY_PARAMETER,true>,size_t *)' being compiled
with
[
MemFunc=int (__thiscall A::* )(int,int **,size_t *)
]
I figured it out!
The issue was the return type of UnwrapParameter. Once I changed the declaration of it to
template <typename T>
auto UnwrapParameter(T in_param) -> decltype(Impl::ParameterUnwrapper<T>::UnwrapParameter(in_param))
It compiled. Shame the compiler didn't complain about the definition of that function, rather than trusting its declared return value.
I have some other problems right now but at least I've made progress.

Wrapping a template function with boost.python

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;
}