Continuous arguments without conversion when converting Ts

(This question follows from this answer )

I am trying to adapt a trampoline function that currently goes through a variable number of arguments.

I would like it to convert any PyObject* pyob to Object{pyob} , but forward all other arguments through.

So (void* self, int, PyObject*, float)(int, Object, float)

In this example, the first argument to self is removed. It always happens. Of the remaining arguments, one of them is of type PyObject * and, therefore, requires conversion to Object.

Here is the function:

 template <typename T, T t> struct trap; template <typename R, typename... Args, R(Base::*t)(Args...)> struct trap<R(Base::*)(Args...), t> { static R call(void* s, Args... args) { std::cout << "trap:" << typeid(t).name() << std::endl; try { return (get_base(s)->*t)(std::forward<Args>(args)...); } catch (...) { std::cout << "CAUGHT" << std::endl; return std::is_integral<R>::value ? static_cast<R>(-42) : static_cast<R>(-3.14); } } }; 

This does not seem to be forwarding arguments. I think he is making a copy of each argument. I tried:

 call(void* s, Args&&... args) 

But this just causes compiler errors.

Full test case here

How can I fix a function to completely redirect all arguments except those of the type PyObject * that it should convert?

+1
source share
2 answers

Arguments don't seem to be forwarded

You cannot ideally redirect arguments to a function that is not a template, or that is called through a pointer to a function, just like you. Perfect-forwarding includes the output of a template argument that is not executed when the function is called through a pointer - this pointer indicates the specific creation of the function template.

In the std::forward<Args>(args) expression, you can use the move constructor to copy-initialize the parameters of the target function from those call arguments that are passed by value (or using a hard-coded rvalue link), or let them be linked by an rvalue link - you these instances will no longer be needed, you can freely move from them while maintaining at least one copy operation. (It can be as simple as static_cast<Args&&>(args)... because it is just a link crashing).


I would like it to convert any PyObject* pyob to Object{pyob} , but forward all other arguments. How can I fix a function for perfection - move all arguments except those of the type PyObject* that it should convert?

 #include <utility> template <typename T, typename U> T&& forward_convert(U&& u) { return std::forward<T>(std::forward<U>(u)); } template <typename T> Object forward_convert(PyObject* a) { return Object{a}; } // ... return (get_base(s)->*t)(forward_convert<Args>(args)...); 

To replace any occurrence of Object with PyObject* when creating the signature of the call function and only then conditionally forward or convert the arguments, you must do the following:

 template <typename T> struct replace { using type = T; }; template <> struct replace<Object> { using type = PyObject*; }; // you may probably want some more cv-ref specializations: //template <> //struct replace<Object&> { using type = PyObject*; }; template <typename T, T t> struct trap; template <typename R, typename... Args, R(Base::*t)(Args...)> struct trap<R(Base::*)(Args...), t> { static R call(void* s, typename replace<Args>::type... args) { try { return (get_base(s)->*t)(forward_convert<typename replace<Args>::type>(args)...); } catch (...) { return std::is_integral<R>::value ? static_cast<R>(-42) : static_cast<R>(-3.14); } } }; 

Demo

+4
source

You need to change the call (note that I will introduce Ts in addition to Args ).

 template <typename ... Ts> static R call(void* s, Ts&&... args) { std::cout << "trap:" << typeid(t).name() << std::endl; try { return (get_base(s)->*t)(std::forward<Ts>(args)...); } catch (...) { std::cout << "CAUGHT" << std::endl; return std::is_integral<R>::value ? static_cast<R>(-42) : static_cast<R>(-3.14); } } 
+2
source

Source: https://habr.com/ru/post/1210771/


All Articles