我无法通过使用模板特征抽象出三个相似的函数。
这是我的代码:
extern "C" PyObject* M_method_noargs_call_handler ( PyObject* _self_and_name_tuple, PyObject* );
extern "C" PyObject* M_method_varargs_call_handler( PyObject* _self_and_name_tuple, PyObject* _args );
extern "C" PyObject* M_method_keyword_call_handler( PyObject* _self_and_name_tuple, PyObject* _args, PyObject* _keywords );
template<TEMPLATE_TYPENAME T>
class ExtModule : public ExtModuleBase
{
public:
ExtModule( const char* name ) : ExtModuleBase( name ) { }
virtual ~ExtModule() { }
protected:
typedef std::map< std::string, MethodDefExt<T>* > method_map_t;
using F0 = typename MethodDefExt<T>::F0;
using F1 = typename MethodDefExt<T>::F1;
using F2 = typename MethodDefExt<T>::F2;
static constexpr auto& h0 = M_method_noargs_call_handler;
static constexpr auto& h1 = M_method_varargs_call_handler;
static constexpr auto& h2 = M_method_keyword_call_handler;
static void add_noargs_method ( const char* name, F0 f ) {
methods()[ std::string(name) ] = new MethodDefExt<T>( name, f, h0 ); }
static void add_varargs_method( const char* name, F1 f ) {
methods()[ std::string(name) ] = new MethodDefExt<T>( name, f, h1 ); }
static void add_keyword_method( const char* name, F2 f ) {
methods()[ std::string(name) ] = new MethodDefExt<T>( name, f, h2 ); }
:
}
我想将所有这三种方法合并为一个 add_method ,其中包含三个重载,即 F0 F1 < / strong>和 F2 函数类型。
请注意,关联的处理程序 h0 , h1 , h2 属于不同类型。
我试图使用特征解决它:
template<typename> struct h_trait;
template<> struct h_trait<F0> { static constexpr auto& h = h0; };
template<> struct h_trait<F1> { static constexpr auto& h = h1; };
template<> struct h_trait<F2> { static constexpr auto& h = h2; };
template< typename F >
static void add_method ( const char* name, F func )
{
methods()[ std::string(name) ] =
new MethodDefExt<T>( name, func, h_trait<F>::h );
}
但这失败了:
Explicit specialization of 'h_trait' in class scope
现在 F0 F1 F2 本身依赖于 T ,所以不幸的是我不能在课堂定义之外采取这些特征(我不认为) ...?)
我知道这可能是荒谬的过度结构,但有没有办法实现这个目标?
PS这里是MethodDefExt:
template<class T>
class MethodDefExt //: public PyMethodDef
{
public:
typedef Object (T::*F0)( );
typedef Object (T::*F1)( const Tuple& args );
typedef Object (T::*F2)( const Tuple& args, const Dict& kws );
// NOARGS
MethodDefExt (
const char* _name,
F0 _function,
H0 _handler
)
{
meth_def.ml_name = const_cast<char *>( _name );
meth_def.ml_meth = reinterpret_cast<PyCFunction>( _handler );
meth_def.ml_flags = METH_NOARGS;
f0 = _function;
}
// VARARGS
MethodDefExt (
const char* _name,
F1 _function,
H1 _handler
)
{
meth_def.ml_name = const_cast<char *>( _name );
meth_def.ml_meth = reinterpret_cast<PyCFunction>( _handler );
meth_def.ml_flags = METH_VARARGS;
f1 = _function;
}
// VARARGS + KEYWORD
MethodDefExt (
const char* _name,
F2 _function,
H2 _handler
)
{
meth_def.ml_name = const_cast<char *>( _name );
meth_def.ml_meth = reinterpret_cast<PyCFunction>( _handler );
meth_def.ml_flags = METH_VARARGS | METH_KEYWORDS;
f2 = _function;
}
~MethodDefExt() { }
PyMethodDef meth_def;
F0 f0 = nullptr;
F1 f1 = nullptr;
F2 f2 = nullptr;
Object py_method;
};
} //命名空间Py
答案 0 :(得分:2)
假设您首选的策略是将h_trait移到课堂外。您面临的问题是您目前在依赖类型方面完全专注于h_trait(即F0和F1取决于T)。既然你想要你的类型的灵活性,你可能会想到专门研究一个非依赖的&#34;方式,例如:
template <typename T>
struct h_trait;
template <typename T>
struct h_trait<typename MethodDefExt<T>::F0> {...} // can't specialize this way!
但是您很快就会注意到,在此上下文中无法推断出T,因为任何旧的MethodDefExt<T>
都可能产生匹配::F0
的类型。
我们可以专注于:
template <>
struct h_trait<MethodDefExt<SPECIFIC_TYPE>::F0> { ... }
但是我们必须专注于可能使用的每种可能的类型。
所以,让我们混合方法和部分专门化h_trait:我们将推导出一个模板参数,并根据推导出的那个指定另一个:
#include <iostream>
void h0(int) { std::cout << "h0\n"; }
void h1(int,char) { std::cout << "h1\n"; }
template <typename T>
struct MethodDefExt {
typedef void(T::*F0)(int);
typedef void(T::*F1)(int,char);
};
template <typename, typename>
struct h_trait;
template <typename T>
struct h_trait<T, typename MethodDefExt<T>::F0>
{
static constexpr auto& h = h0;
};
template <typename T>
struct h_trait<T, typename MethodDefExt<T>::F1>
{
static constexpr auto& h = h1;
};
template <typename T>
struct YourClass {
using F0 = typename MethodDefExt<T>::F0;
using F1 = typename MethodDefExt<T>::F1;
template <typename F>
void do_internal(F f)
{
h_trait<T,F> b;
b.h(1); // calls our awkwardly bound function just
// to demonstrate
}
void foo() {
F0 f{};
do_internal(f); // doit(F0{}); // ICE IN gcc 4.8.1
}
};
struct A {};
int main() {
YourClass<A> b; // doesn't work with non-class type parameter
b.foo();
}