Ant*_*ine 32 c++ metaprogramming traits type-traits
是否有可能写出一个类型特征,比如说is_callable<T>一个对象是否已operator()定义?如果调用运算符的参数事先已知,则很容易,但在一般情况下则不行.当且仅当至少有一个重载调用运算符被定义时,我希望特征返回true.
这个问题是相关的,并且有一个很好的答案,但它不适用于所有类型(仅限于 - 可int转换类型).此外,std::is_function工作,但只适用于正确的C++函数,而不是函子.我正在寻找更通用的解决方案.
jro*_*rok 35
我认为这个特性可以满足您的需求.它可以检测到operator()任何类型的签名,即使它已经过载也是如果它被模板化了:
template<typename T>
struct is_callable {
private:
typedef char(&yes)[1];
typedef char(&no)[2];
struct Fallback { void operator()(); };
struct Derived : T, Fallback { };
template<typename U, U> struct Check;
template<typename>
static yes test(...);
template<typename C>
static no test(Check<void (Fallback::*)(), &C::operator()>*);
public:
static const bool value = sizeof(test<Derived>(0)) == sizeof(yes);
};
Run Code Online (Sandbox Code Playgroud)
该原则基于Member Detector习语.实际上,如果你传递一个非类型的类型,它将无法编译,但这不应该很难解决,我只是为了简洁而将它留下.您还可以将其扩展为报告函数的true.
当然它没有给你任何关于签名的任何信息operator(),但我相信这不是你要求的,对吧?
编辑Klaim:
它非常简单,可以false使用非类类型工作(返回).如果将上述类重命名为is_callable_impl,则可以编写此类,例如:
template<typename T>
struct is_callable
: std::conditional<
std::is_class<T>::value,
is_callable_impl<T>,
std::false_type
>::type
{ };
Run Code Online (Sandbox Code Playgroud)
Cha*_*acy 10
这里的答案很有帮助,但我来到这里想要的东西也可以发现某些东西是否可以调用,无论它是否恰好是一个对象或一个经典函数. jrok对问题的这个方面的答案,唉,没有用,因为std::conditional实际上评估了双臂的类型!
所以,这是一个解决方案:
// Note that std::is_function says that pointers to functions
// and references to functions aren't functions, so we'll make our
// own is_function_t that pulls off any pointer/reference first.
template<typename T>
using remove_ref_t = typename std::remove_reference<T>::type;
template<typename T>
using remove_refptr_t = typename std::remove_pointer<remove_ref_t<T>>::type;
template<typename T>
using is_function_t = typename std::is_function<remove_refptr_t<T>>::type;
// We can't use std::conditional because it (apparently) must determine
// the types of both arms of the condition, so we do it directly.
// Non-objects are callable only if they are functions.
template<bool isObject, typename T>
struct is_callable_impl : public is_function_t<T> {};
// Objects are callable if they have an operator(). We use a method check
// to find out.
template<typename T>
struct is_callable_impl<true, T> {
private:
struct Fallback { void operator()(); };
struct Derived : T, Fallback { };
template<typename U, U> struct Check;
template<typename>
static std::true_type test(...);
template<typename C>
static std::false_type test(Check<void (Fallback::*)(), &C::operator()>*);
public:
typedef decltype(test<Derived>(nullptr)) type;
};
// Now we have our final version of is_callable_t. Again, we have to take
// care with references because std::is_class says "No" if we give it a
// reference to a class.
template<typename T>
using is_callable_t =
typename is_callable_impl<std::is_class<remove_ref_t<T>>::value,
remove_ref_t<T> >::type;
Run Code Online (Sandbox Code Playgroud)
但最后,对于我的应用程序,我真的只想知道你是否可以说f()(即,没有参数调用它),所以我改为使用更简单的东西.
template <typename T>
constexpr bool noarg_callable_impl(
typename std::enable_if<bool(sizeof((std::declval<T>()(),0)))>::type*)
{
return true;
}
template<typename T>
constexpr bool noarg_callable_impl(...)
{
return false;
}
template<typename T>
constexpr bool is_noarg_callable()
{
return noarg_callable_impl<T>(nullptr);
}
Run Code Online (Sandbox Code Playgroud)
事实上,我走得更远了.我知道这个函数应该返回一个int,所以不要只是检查我是否可以调用它,我也检查了返回类型,通过更改enable_if为:
typename std::enable_if<std::is_convertible<decltype(std::declval<T>()()),
int>::value>::type*)
Run Code Online (Sandbox Code Playgroud)
希望这有助于某人!
这是一个使用C++ 11的可能解决方案,无需知道仿函数的调用运算符的签名即可工作,但只有仿函数没有多个重载operator ():
#include <type_traits>
template<typename T, typename = void>
struct is_callable : std::is_function<T> { };
template<typename T>
struct is_callable<T, typename std::enable_if<
std::is_same<decltype(void(&T::operator())), void>::value
>::type> : std::true_type { };
Run Code Online (Sandbox Code Playgroud)
这是你如何使用它:
struct C
{
void operator () () { }
};
struct NC { };
struct D
{
void operator () () { }
void operator () (int) { }
};
int main()
{
static_assert(is_callable<C>::value, "Error");
static_assert(is_callable<void()>::value, "Error");
auto l = [] () { };
static_assert(is_callable<decltype(l)>::value, "Error");
// Fires! (no operator())
static_assert(is_callable<NC>::value, "Error");
// Fires! (several overloads of operator ())
static_assert(is_callable<D>::value, "Error");
}
Run Code Online (Sandbox Code Playgroud)
这是一个实例.
| 归档时间: |
|
| 查看次数: |
8144 次 |
| 最近记录: |