Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/127.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;确定类型是否可调用的元函数_C++_C++11_Metaprogramming - Fatal编程技术网

C++ C++;确定类型是否可调用的元函数

C++ C++;确定类型是否可调用的元函数,c++,c++11,metaprogramming,C++,C++11,Metaprogramming,是否可以编写一个确定类型是否可调用的C++(0x)元函数 所谓可调用类型,我指的是函数类型、函数指针类型、函数引用类型(它们由boost::function\u types::is\u callable\u builtin)检测)、lambda类型和任何重载运算符()的类(也可能是任何一个类,都有隐式转换操作符,但这不是绝对必要的) 编辑:元函数应该检测带有任何签名的操作符(),包括模板化的操作符()。我认为这是困难的部分 编辑:下面是一个用例: template <typename Pr

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

所谓可调用类型,我指的是函数类型、函数指针类型、函数引用类型(它们由
boost::function\u types::is\u callable\u builtin
)检测)、lambda类型和任何重载
运算符()的类(也可能是任何一个类,都有隐式转换操作符,但这不是绝对必要的)

编辑:元函数应该检测带有任何签名的
操作符()
,包括模板化的
操作符()
。我认为这是困难的部分

编辑:下面是一个用例:

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};
}
模板
结构与谓词
{
模板
布尔运算符()(常量参数和参数)
{
返回谓词1(arg)和谓词2(arg);
}
谓词1谓词1;
谓词2谓词2;
};
模板
启用_if::type
运算符&(谓词1谓词1、谓词2谓词2)
{
返回和_谓词{predicate1,predicate2};
}

是可调用的
是我想要实现的。

这是一个非常有趣的问题。我一直很困惑

我想我成功地对疯狂的Eddie的代码进行了修改,允许使用任意数量的参数,但是,它确实使用可变模板,并且它确实需要指定您希望调用“可调用”对象的参数。长话短说,我在gcc 4.6.0上按预期运行并工作:

EDIT:也可以使用std::result\u实用程序,但是它不起作用,因为它需要
typename
来消除
std::result\u of::type
的歧义,这打破了Sfinae

#include <iostream>
#include <type_traits>

template < typename PotentiallyCallable, typename... Args>
struct is_callable
{
  typedef char (&no)  [1];
  typedef char (&yes) [2];

  template < typename T > struct dummy;

  template < typename CheckType>
  static yes check(dummy<decltype(std::declval<CheckType>()(std::declval<Args>()...))> *);
  template < typename CheckType>
  static no check(...);

  enum { value = sizeof(check<PotentiallyCallable>(0)) == sizeof(yes) };
};

int f1(int,double) { return 0; };
typedef int(*f1_type)(int,double) ; //this is just to have a type to feed the template.

struct Foo { };

struct Bar {
  template <typename T>
  void operator()(T) { };
};

int main() {
  if( is_callable<f1_type,int,double>::value )
    std::cout << "f1 is callable!" << std::endl;
  if( is_callable<Foo>::value )
    std::cout << "Foo is callable!" << std::endl;
  if( is_callable<Bar,int>::value )
    std::cout << "Bar is callable with int!" << std::endl;
  if( is_callable<Bar,double>::value )
    std::cout << "Bar is callable with double!" << std::endl;
};
#包括
#包括
模板
结构是可调用的
{
typedef字符(&no)[1];
typedef字符(&yes)[2];
模板结构虚拟;
模板
静态是检查(虚拟*);
模板
静态不检查(…);
枚举{value=sizeof(检查(0))==sizeof(是)};
};
int f1(int,double){返回0;};
typedef int(*f1_type)(int,double);//这只是为了给模板提供一个类型。
结构Foo{};
结构条{
模板
void运算符()(T){};
};
int main(){
if(可调用::值)

std::cout给定类型T的非模板T::运算符()的存在可通过以下方式检测:

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)  )
模板//检测常规运算符()
静态字符测试(decltype(&C::operator());
模板//最差匹配
静态字符(&测试(…)[2];
静态常量布尔值=(sizeof(测试(0))
模板化操作员的存在可通过以下方式检测:

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...
template//detect 1-arg运算符()
静态字符测试(int,decltype((*(F*)0)((*(A*)0)))=0;
模板//检测2-arg运算符()
静态字符测试(int,decltype((*(F*)0)((*(A*)0),(*(B*)0))=0);
//…检测N-arg运算符()
模板//最差匹配
静态字符(&测试(…)[2];
静态常量布尔值=(sizeof(test(0))==1)|
(sizeof(test(0))==1);//等等。。。
但是,这两种方法不能很好地结合在一起,因为如果C有一个模板化的函数调用操作符,decltype(&C::operator())将产生一个错误。解决方案是首先对模板化操作符运行一系列检查,然后检查一个常规操作符()当且仅当无法找到模板时。这是通过在找到模板时将非模板检查专门化为无操作来完成的

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;
};
模板
结构具有\u常规\u调用\u运算符
{
模板//检测常规运算符()
静态字符测试(decltype(&C::operator());
模板//最差匹配
静态字符(&测试(…)[2];
静态常量布尔值=(sizeof(test(0))==1);
};
模板
结构具有\u常规\u调用\u运算符
{
静态常量布尔值=真;
};
模板
结构具有调用运算符
{
模板//检测1-arg运算符()
静态字符测试(int,decltype((*(F*)0)((*(A*)0)))=0;
模板//检测2-arg运算符()
静态字符测试(int,decltype((*(F*)0)((*(A*)0),(*(B*)0))=0);
模板//检测3-arg运算符()
静态字符测试(int,decltype((*(F*)0)((*(A*)0),(*(B*)0),(*(C*)0))=0;
模板//最差匹配
静态字符(&测试(…)[2];
静态常量bool OneArg=(sizeof(test(0))==1);
静态常量booltwoarg=(sizeof(test(0))==1);
静态常量bool ThreeArg=(sizeof(test(0))==1);
静态常量bool HasTemplatedOperator=OneArg | | | TwoArg | | ThreeArg;
static const bool value=has_regular_call_operator::value;
};

如前所述,如果arity总是1,那么检查应该更简单。我认为不需要任何额外的类型特征或库设施来实现这一点。

随着我们在c++11(及更高版本)中的集体经验的出现,可能是时候重新讨论这个问题了

这种小性格似乎适合我:

#include <iostream>
#include <utility>

template<class F, class...Args>
struct is_callable
{
    template<class U> static auto test(U* p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type());
    template<class U> static auto test(...) -> decltype(std::false_type());

    static constexpr bool value = decltype(test<F>(0))::value;
};

为什么要检查一个对象是否可调用?您试图做什么?例如,编写一个重载运算符&&它接受两个谓词A和B并返回一个谓词C,这样C(x)iff.A(x)&&B(x)显然,不把这样的操作员限制在可调用对象上会造成其他地方的破坏。我喜欢C++模板如何要求你不匹配你不喜欢的东西,而不是匹配你所做的事情。在D,这只会转化为一个预先存在的模板<代码>可调用!,其定义与C++中的间接一样:@ HythMuleCord4:模板化的<代码>操作程序()
甚至不是最糟糕的,想想多个重载和SFINAE应用于某些…这里有一个C++03版本:。当然它只适用于一组特定的参数类型,但它适用于任何可调用的实体。也就是说,包括函数指针、引用和带有代理调用函数的类类型。I
#include <iostream>
#include <utility>

template<class F, class...Args>
struct is_callable
{
    template<class U> static auto test(U* p) -> decltype((*p)(std::declval<Args>()...), void(), std::true_type());
    template<class U> static auto test(...) -> decltype(std::false_type());

    static constexpr bool value = decltype(test<F>(0))::value;
};
template<class F, class...Args, typename std::enable_if<is_callable<F, Args&&...>::value>::type* = nullptr>
void test_call(F, Args&&...args)
{
    std::cout << "callable" << std::endl;
}

template<class F, class...Args, typename std::enable_if<not is_callable<F, Args&&...>::value>::type* = nullptr>
void test_call(F, Args&&...args)
{
    std::cout << "not callable" << std::endl;
}

extern void f3(int, const std::string&)
{

}

int main()
{
    auto f1 = [](int, std::string) {};
    test_call(f1, 0, "hello");
    test_call(f1, "bad", "hello");

    std::function<void(int, const std::string&)> f2;
    test_call(f2, 0, "hello");
    test_call(f2, "bad", "hello");

    test_call(f3, 0, "hello");
    test_call(f3, "bad", "hello");

}
callable
not callable
callable
not callable
callable
not callable