转换T-s时的正向非T参数

问题描述 投票:1回答:2

(此问题来自this answer

我正在尝试调整一个蹦床功能,该功能目前仅通过可变数量的参数传递。

我想让它将任何参数PyObject* pyob转换为Object{pyob},但转发所有其他参数。

所以(void* self, int, PyObject*, float)-> (int, Object, float)

在该示例中,第一个self参数被删除。这总是发生。在其余参数中,其中一个是PyObject*类型,因此需要转换为Object。

这里是功能:

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

似乎没有转发参数。我认为它正在复制每个论点。我已经尝试过:

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

但是那只会产生编译器错误。

完整的测试用例是here

如何修复该函数,以完善除PyObject*类型之外的所有参数,应将其转换?

c++ c++11 templates variadic-templates perfect-forwarding
2个回答
4
投票

似乎不是转发参数

您不能perfectly-forward并非模板的函数的参数,或像您一样通过函数的指针调用的参数。 Perfect-forwarding涉及到template arguments deduction,当您通过指针调用函数时,该指针不会发生-该指针指向函数模板的具体实例化

std::forward<Args>(args)表达式在那里可能利用move-constructorby value传递的call的那些参数中复制初始化目标函数的参数。硬编码的右值引用),或者让它们受右值引用约束-您将不再需要这些实例,可以自由地从[[move-from它们实例化,从而节省至少一个复制操作。 (它可能像static_cast<Args&&>(args)...一样简单,因为它只是一个参考折叠)。


我希望它将任何参数PyObject* pyob转换为Object{pyob},但转发所有其他参数。如何修复该函数,以完善除PyObject*类型之外的所有参数(应转换的参数)?

#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)...);

[在创建Object函数的签名时用PyObject*替换任何出现的call,然后才有条件地转发或转换参数,您应该执行以下操作:

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    

2
投票
您必须将呼叫更改为(请注意,除了Ts外,我还介绍了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); } }

© www.soinside.com 2019 - 2024. All rights reserved.