C ++元函数确定类型是否可调用 [英] C++ metafunction to determine whether a type is callable

查看:61
本文介绍了C ++元函数确定类型是否可调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以编写C ++(0x)元函数来确定类型是否可调用?

Is it possible to write a C++(0x) metafunction that determines whether a type is callable?

通过可调用类型,我的意思是函数类型,函数指针类型,函数引用类型(由boost::function_types::is_callable_builtin检测到),lambda类型以及任何带有operator()重载的类(可能还包括具有隐式转换的任何类)运算符之一,但这不是绝对必要的.

By callable type I mean a function type, function pointer type, function reference type (these are detected by boost::function_types::is_callable_builtin), lambda types, and any class with an overloaded operator() (and maybe any class with an implicit conversion operator to one of these, but that's not absolutely necessary).

编辑:元功能应该检测带有任何签名(包括模板化的operator())的operator()的存在.我相信这是困难的部分.

EDIT: The metafunction should detect the presence of an operator() with any signature, including a templated operator(). I believe this is the difficult part.

编辑:这是一个用例:

template <typename Predicate1, typename Predicate2>
struct and_predicate
{
    template <typename ArgT>
    bool operator()(const ArgT& arg)
    {
        return predicate1(arg) && predicate2(arg);
    }

    Predicate1 predicate1;
    Predicate2 predicate2;
};

template <typename Predicate1, typename Predicate2>
enable_if<ice_and<is_callable<Predicate1>::value,
                  is_callable<Predicate2>::value>::value,
          and_predicate<Predicate1, Predicate2>>::type
operator&&(Predicate1 predicate1, Predicate2 predicate2)
{
    return and_predicate<Predicate1, Predicate2>{predicate1, predicate2};
}

is_callable是我要实现的.

推荐答案

对于给定类型 T ,非模板化的 T :: operator()的存在可以被以下人员检测到:

The presence of a non-templated T::operator() for a given type T can be detected by:

template<typename C> // detect regular operator()
static char test(decltype(&C::operator()));

template<typename C> // worst match
static char (&test(...))[2];

static const bool value = (sizeof( test<T>(0)  )

可以通过以下方式检测模板操作符的存在:

The presence of a templated operator can be detected by:

template<typename F, typename A> // detect 1-arg operator()
static char test(int, decltype( (*(F*)0)( (*(A*)0) ) ) = 0);

template<typename F, typename A, typename B> // detect 2-arg operator()
static char test(int, decltype( (*(F*)0)( (*(A*)0), (*(B*)0) ) ) = 0);

// ... detect N-arg operator()

template<typename F, typename ...Args> // worst match
static char (&test(...))[2];

static const bool value = (sizeof( test<T, int>(0)  ) == 1) || 
                          (sizeof( test<T, int, int>(0)  ) == 1); // etc...

但是,由于C具有模板化函数调用运算符,因此 decltype(& C :: operator())会产生错误,因此这两者不能很好地配合使用.解决方案是先对模板化运算符进行一系列检查,然后在找不到模板化运算符的情况下检查常规的operator().这是通过将非模板检查专门化为无操作(如果找到了模板检查)来完成的.

However, these two do not play nicely together, as decltype(&C::operator()) will produce an error if C has a templated function call operator. The solution is to run the sequence of checks against a templated operator first, and check for a regular operator() if and only if a templated one can not be found. This is done by specializing the non-templated check to a no-op if a templated one was found.

template<bool, typename T>
struct has_regular_call_operator
{
  template<typename C> // detect regular operator()
  static char test(decltype(&C::operator()));

  template<typename C> // worst match
  static char (&test(...))[2];

  static const bool value = (sizeof( test<T>(0)  ) == 1);
};

template<typename T>
struct has_regular_call_operator<true,T>
{
  static const bool value = true;
};

template<typename T>
struct has_call_operator
{
  template<typename F, typename A> // detect 1-arg operator()
  static char test(int, decltype( (*(F*)0)( (*(A*)0) ) ) = 0);

  template<typename F, typename A, typename B> // detect 2-arg operator()
  static char test(int, decltype( (*(F*)0)( (*(A*)0), (*(B*)0) ) ) = 0);

  template<typename F, typename A, typename B, typename C> // detect 3-arg operator()
  static char test(int, decltype( (*(F*)0)( (*(A*)0), (*(B*)0), (*(C*)0) ) ) = 0);

  template<typename F, typename ...Args> // worst match
  static char (&test(...))[2];

  static const bool OneArg = (sizeof( test<T, int>(0)  ) == 1);
  static const bool TwoArg = (sizeof( test<T, int, int>(0)  ) == 1);
  static const bool ThreeArg = (sizeof( test<T, int, int, int>(0)  ) == 1);

  static const bool HasTemplatedOperator = OneArg || TwoArg || ThreeArg;
  static const bool value = has_regular_call_operator<HasTemplatedOperator, T>::value;
};

如上所述,如果Arity始终为1,则检查应该更简单.我认为不需要其他任何类型特征或库功能就可以正常工作.

If the arity is always one, as discussed above, then the check should be simpler. I do not see the need for any additional type traits or library facilities for this to work.

这篇关于C ++元函数确定类型是否可调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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