模板编程:specialization和enable_if [英] Template programming: specialization and enable_if

查看:174
本文介绍了模板编程:specialization和enable_if的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用libffi,我做了一个类与类似的模板 std :: function (ie class Func< Ret (Args ...)> {/ * ... * /}; 。我想转换返回类型( Ret )每个参数类型( Args )转换为相应的libffi类型(参见为了参考)。到目前为止我想出了这个:

I'm working with libffi and I've made a class with a similar template to std::function (i.e class Func<Ret (Args...)> { /* ... */};. I want to convert the return type (Ret) and each argument type (Args) to their corresponding libffi type (see this for reference). So far I've come up with 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函数的实现如下: p>

Where the GetFFIType function is implemented as the following:

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 )会发生运行时错误。我如何避免这一点,并使这个函数确定一个类型是否有效(一个原始类型)或编译期间不?

This works, but obviously there is some room for improvements. If the type is invalid (i.e a class or a structure) it is not identified at compile-time (a runtime-error occurs instead using assert). How would I avoid this, and make this function determine whether a type is valid (a primitive type) or not during compilation?

我也不喜欢我的方式,在枚举的情况下的底层类型。我宁愿使用 std :: underlying_type< T> 改为(注释掉在代码中),但它发出编译错误,如果类型是一个void指针c $ c> type_traits:1762:38:error:'void *'不是枚举类型)

I also dislike the way I am identifying the underlying type in case of enums. I would prefer using std::underlying_type<T> instead (commented out in the code) but it issues compile-errors if the type is for example a void pointer (type_traits:1762:38: error: ‘void*’ is not an enumeration type)

使用 std :: enable_if 但没有成功...请告诉我是否应该解释一些东西,如果它听起来有点模糊!

I tried to achieve this behavior using std::enable_if but without success... Do tell if I should explain something in case it sounded a bit fuzzy!

摘要:我想要获得GetFFIType函数来确定编译期间的所有内容,并且函数应该只支持基本类型(参见更广泛的参考)

Summary: I want to get the GetFFIType function to determine everything during compilation and the function should only support primitive types (see this for a more extensive reference)

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

Sorry for the title, nothing better came to mind :(

推荐答案

将逻辑放入类模板而不是函数模板将允许部分特化,我们也可以SFINAE技巧的优点:

Putting the logic inside a class template rather than a function template will allow for partial specializations, which we can also take advantage of for SFINAE tricks:

// Second parameter is an implementation detail
template<typename T, typename Sfinae = std::true_type>
struct ToFFIType;

// Front-end
template<typename T>
ffi_type* GetFFIType()
{ return ToFFIType<T>::make(); }

// Primary template where we end up if we don't know what to do with the type
template<typename T, typename = std::true_type>
struct ToFFIType {
    static_assert( dependent_false_type<T>::value,
                   "Write your clever error message to explain why we ended up here" );

    static ffi_type* make() = delete;
};

// Trait-like to match what we want with ffi_type_pointer
template<typename T>
struct treat_as_pointer: or_<
    std::is_pointer<T>
    , std::is_array<T>
    , std::is_reference<T>
    , std::is_function<T>
> {};

template<typename T>
struct ToFFIType<T, typename treat_as_pointer<T>::type> {
    static ffi_type* make()
    { return &fii_type_pointer; }
};

// Matches enumeration types
template<typename T>
struct ToFFIType<T, typename std::is_enum<T>::type> {
    static ffi_type* make()
    {
        return ToFFIType<typename std::underlying_type<T>::type>::make();
    }
};

总专业化可以直接写入,所以我不会显示。虽然请注意,您可以选择替代 std :: is_integral 并打开 sizeof(T)如果你想,类似于你做的工作 std :: underlying_type

The total specializations are straightforward to write so I won't show them. Although note that you can choose to instead match e.g. std::is_integral and switch on sizeof(T) if you want, similar to what you did to work around std::underlying_type.

最后是上面代码中假设的两个实用程序的两个建议实现;显然你不需要逐字地使用它们,只要你以同样的方式写别的东西。

Finally here are two suggested implementations of the two utilities which are assumed in the above code; obviously you don't need to use them verbatim as long as you write something else along in the same vein.

// Same functionality as std::false_type but useful
// for static_assert in templates
template<typename Dummy>
struct dependent_false_type: std::false_type {};

// Disjunction of boolean TMP integral constants
// Take care to inherit from std::true_type/std::false_type so
// the previous SFINAE trick works
template<typename... T>
struct or_: std::false_type {};

// There likely are better implementations
template<typename Head, typename... Tail>
struct or_<Head, Tail...>: std::conditional<
    Head::value
    , std::true_type              // short circuit to desired base
    , typename or_<Tail...>::type // or inherit from recursive base
>::type {}; // Note: std::conditional is NOT the base

这篇关于模板编程:specialization和enable_if的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆