C++ C++;确定类型是否可调用的元函数
是否可以编写一个确定类型是否可调用的C++(0x)元函数 所谓可调用类型,我指的是函数类型、函数指针类型、函数引用类型(它们由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
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