我使用以下方式,在 stackoverflow 答案中提出来确定一个类型是否可调用:
template <typename T>
struct is_callable
{
typedef char (& yes)[1];
typedef char (& no)[2];
// we need a template here to enable SFINAE
template <typename U>
static yes deduce(char (*)[sizeof(&U::operator())]);
// fallback
template <typename> static no deduce(...);
static bool constexpr value = std::is_function<T>::value || (sizeof(deduce<T>(0)) == sizeof(yes));
};
但是当一个类有多个 operator() 重载时它会失败:
#include <iostream>
template <typename T>
class A
{
T operator()();
T operator()(T a);
T operator()(T a, T b);
};
std::cout << is_callable<A<int>>::value; // false
是否可以确定一个类型是否具有重载 operator() 的任何变体(模板化与否,一个或多个)?
首先,您需要将 A 声明为完整类型(例如 A<int>
)。
仅通过展开和比较它的 operator()
来检查对象是否可调用是不可靠的因为它会在模板化或重载仿函数上失败。
我是 using the following piece of code
检测对象是否可以使用给定的函数签名 ( ReturnType(Arguments...)
)
这也适用于重载或模板化 operator()
因为代码试图用给定的参数调用对象
而不是比较其未包装的签名 operator()
.
作为一个小补充,还可以检查对象是否可从 const、volatile 或右值上下文调用。
#include <type_traits>
template<typename Fn>
struct impl_is_callable_with_qualifiers;
template<typename ReturnType, typename... Args>
struct impl_is_callable_with_qualifiers<ReturnType(Args...)>
{
template<typename T>
static auto test(int)
-> typename std::is_convertible<
decltype(std::declval<T>()(std::declval<Args>()...)),
ReturnType
>;
template<typename T>
static auto test(...)
-> std::false_type;
};
template<bool Condition, typename T>
using add_const_if_t = typename std::conditional<
Condition,
typename std::add_const<T>::type,
T
>::type;
template<bool Condition, typename T>
using add_volatile_if_t = typename std::conditional<
Condition,
typename std::add_volatile<T>::type,
T
>::type;
template<bool Condition, typename T>
using add_lvalue_if_t = typename std::conditional<
Condition,
typename std::add_lvalue_reference<T>::type,
T
>::type;
template<typename T, typename Fn, bool Const, bool Volatile, bool RValue>
using is_callable_with_qualifiers = decltype(impl_is_callable_with_qualifiers<Fn>::template test<
add_lvalue_if_t<!RValue,
add_volatile_if_t<Volatile,
add_const_if_t<Const,
typename std::decay<T>::type>>>
>(0));
无法确定类型是否具有任何重载变体 operator()
,
但是,您可以测试特定类型或对多种类型执行测试以检测“可能的”模板。
涵盖您问题中的代码的示例是:
#include <iostream>
template<typename T>
class A
{
public:
A() = default;
T operator()() { return T(); }
T operator()(T a) { return T(); }
T operator()(T a, T b) { return T(); }
};
template <typename TheClass, typename T>
using is_callable = is_callable_with_qualifiers<TheClass, T(T), false, false, false>;
int main()
{
std::cout << is_callable<A<int>, int>::value; // true
}
Demo