c++ - 模板编程 : specialization and enable_if

标签 c++ gcc c++11 libffi

我正在使用 libffi,我已经用与 std::function 类似的模板创建了一个类(即 class Func<Ret (Args...)> { /* ... */}; 。我想将返回类型( Ret )和每个参数类型( Args )转换为它们相应的 libffi 类型(参见 this 以供引用)。到目前为止,我已经想出了这个:

// Member function of 'Func' class
Prepare(void)
{
 // This vector holds all the type structures
 std::vector<ffi_type*> argumentTypes{ GetFFIType<Args>()... };
 ffi_type * returnType = GetFFIType<Ret>();

 // Rest of the code below
 // ....
}

其中GetFFIType函数实现如下:

template <typename T>
ffi_type * GetFFIType(void)
{
    // We will check for any kind of pointer types
    if(std::is_pointer<T>::value || std::is_array<T>::value ||
       std::is_reference<T>::value || std::is_function<T>::value)
        return &ffi_type_pointer;

    if(std::is_enum<T>::value)
        //return GetFFIType<std::underlying_type<T>::type>();
    {
        // Since the size of the enum may vary, we will identify the size
        if(sizeof(T) == ffi_type_schar.size)    return std::is_unsigned<T>::value ? &ffi_type_uchar : &ffi_type_schar;
        if(sizeof(T) == ffi_type_sshort.size)   return std::is_unsigned<T>::value ? &ffi_type_ushort : &ffi_type_sshort;
        if(sizeof(T) == ffi_type_sint.size) return std::is_unsigned<T>::value ? &ffi_type_uint : &ffi_type_sint;
        if(sizeof(T) == ffi_type_slong.size)    return std::is_unsigned<T>::value ? &ffi_type_ulong : &ffi_type_slong;
    }

    assert(false && "cannot identify type");
}

// These are all of our specializations
template <> ffi_type * GetFFIType<void>(void)       { return &ffi_type_void; }
template <> ffi_type * GetFFIType<byte>(void)       { return &ffi_type_uchar; }
template <> ffi_type * GetFFIType<char>(void)       { return &ffi_type_schar; }
template <> ffi_type * GetFFIType<ushort>(void)     { return &ffi_type_ushort; }
template <> ffi_type * GetFFIType<short>(void)      { return &ffi_type_sshort; }
template <> ffi_type * GetFFIType<uint>(void)       { return &ffi_type_uint; }
template <> ffi_type * GetFFIType<int>(void)        { return &ffi_type_sint; }
template <> ffi_type * GetFFIType<ulong>(void)      { return &ffi_type_ulong; }
template <> ffi_type * GetFFIType<long>(void)       { return &ffi_type_slong; }
template <> ffi_type * GetFFIType<float>(void)      { return &ffi_type_float; }
template <> ffi_type * GetFFIType<double>(void)     { return &ffi_type_double; }
template <> ffi_type * GetFFIType<long double>(void)    { return &ffi_type_longdouble; }

这可行,但显然还有一些改进空间。如果类型无效(即类或结构),则在编译时未识别它(发生运行时错误而不是使用 assert )。我如何避免这种情况,并使该函数在编译期间确定类型是否有效(基本类型)?

我也不喜欢在 enum 的情况下识别基础类型的方式秒。我更喜欢使用 std::underlying_type<T>相反(在代码中注释掉)但是如果类型是例如空指针(type_traits:1762:38: error: ‘void*’ is not an enumeration type),它会发出编译错误

我尝试使用 std::enable_if 实现此行为但没有成功......请告诉我是否应该解释一些事情,以防它听起来有点模糊!

总结:我想获取 GetFFIType 函数以确定编译期间的所有内容,并且该函数应该只支持原始类型(请参阅 this 以获得更广泛的引用)

编辑:对不起标题,没有更好的想法:(

最佳答案

重载函数模板比​​专门化它们更容易,通常也更好。我将添加一个带有指针参数的函数版本,这样就可以在没有模板参数列表的情况下调用它:

inline ffi_type * GetFFITypeHelper( void* ) { return &ffi_type_void; }
inline ffi_type * GetFFITypeHelper( byte* ) { return &ffi_type_uchar; }
// ...

然后您可以使用 enable_if 来处理您想要涵盖的更普遍的情况。

template<typename T> auto GetFFITypeHelper( T* ) ->
    std::enable_if< std::is_function<T>::value, ffi_type* >::type
{ return &ffi_type_pointer; }
template<typename T> auto GetFFITypeHelper( T* ) ->
    std::enable_if< std::is_enum<T>::value, ffi_type* >::type
{ return GetFFITypeHelper( static_cast<std::underlying_type<T>::type*>(nullptr) ); }

在声明所有这些重载之后,您想要的版本是:

template<typename T> ffi_type * GetFFIType()
{ return GetFFITypeHelper( static_cast<T*>(nullptr) ); }

关于c++ - 模板编程 : specialization and enable_if,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11398966/

相关文章:

c++ - C++ 编程语言,第 5.9 章练习 1

c++ - Qt5 中的拆分器是不可见的

c++ - 实现迭代器时声明 value_type

c - 预期 ‘=’ , ‘,’ , ‘;’ , ‘asm’ 或 ‘__attribute__’ token 之前的 ‘{’

c++ - “to_string”是't a member of “std”吗?

c++ - initializer_list 结合其他参数

c++ - 如何从 C++ 中的文件中读取乘法字符数组

c++ - ThreadSanitizer FATAL 运行时异常

c - libdl 加载的 "plugins"如何引用加载它们的程序中的符号?

c++ - 链接使用不同版本的 gcc 编译的库