Perfect-forward non-T arguments while converting T-s

冷暖自知 提交于 2019-12-02 04:51:22

It appears not to be forwarding arguments

You can't perfectly-forward arguments of a function which is not a template, or which is invoked through a pointer to a function, like you do. Perfect-forwarding involves a template argument deduction, which doesn't take place when you invoke a function through a pointer - that pointer points to a concrete instantiation of a function template.

The std::forward<Args>(args) expression is there to possibly utilize a move-constructor to copy-initialize the parameters of the target function from those arguments of call that are passed by value (or by a hard-coded rvalue reference), or let them be bound by an rvalue reference - you won't need any more those instances, you are free to move-from them, saving at least one copy operation. (It could be as simple as static_cast<Args&&>(args)..., because it's just a reference collapsing).


I would like to have it convert any argument PyObject* pyob to Object{pyob}, but forward all other arguments through. How can I fix the function to perfect-forward all arguments apart from those of type PyObject*, which 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* while creating the signature of call function, and only then conditionally forward or convert the arguments, you should do what follows:

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

You have to change call to (Note that I 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); 
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!