转换 T-s 时完美转发非 T 参数
Perfect-forward non-T arguments while converting T-s
(这个问题来自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*
之外的所有参数?
您必须将调用更改为(请注意,除了 Args
之外,我还引入了 Ts
)。
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);
}
}
It appears not to be forwarding arguments
您不能像您一样完美转发 不是模板的函数的参数,或者通过指向函数的指针调用的函数。 完美转发涉及模板参数推导,当您通过指针调用函数时不会发生这种情况 - 该指针指向 函数模板的具体实例化。
std::forward<Args>(args)
表达式可能利用 移动构造函数 从 call
的参数复制初始化目标函数的参数通过值(或通过硬编码的右值引用)传递的,或者让它们被右值引用绑定——你将不再需要这些实例,你可以自由地move-from 它们,至少节省了一次复制操作。 (它可以像 static_cast<Args&&>(args)...
一样简单,因为它只是一个引用折叠)。
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)...);
要在创建 call
函数的签名时用 PyObject*
替换任何出现的 Object
,然后才有条件地转发或转换参数,您应该执行以下操作:
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);
}
}
};
(这个问题来自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*
之外的所有参数?
您必须将调用更改为(请注意,除了 Args
之外,我还引入了 Ts
)。
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);
}
}
It appears not to be forwarding arguments
您不能像您一样完美转发 不是模板的函数的参数,或者通过指向函数的指针调用的函数。 完美转发涉及模板参数推导,当您通过指针调用函数时不会发生这种情况 - 该指针指向 函数模板的具体实例化。
std::forward<Args>(args)
表达式可能利用 移动构造函数 从 call
的参数复制初始化目标函数的参数通过值(或通过硬编码的右值引用)传递的,或者让它们被右值引用绑定——你将不再需要这些实例,你可以自由地move-from 它们,至少节省了一次复制操作。 (它可以像 static_cast<Args&&>(args)...
一样简单,因为它只是一个引用折叠)。
I would like to have it convert any argument
PyObject* pyob
toObject{pyob}
, but forward all other arguments through. How can I fix the function to perfect-forward all arguments apart from those of typePyObject*
, 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)...);
要在创建 call
函数的签名时用 PyObject*
替换任何出现的 Object
,然后才有条件地转发或转换参数,您应该执行以下操作:
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);
}
}
};