c++ - 静态检测任何重载的 operator()

标签 c++ c++11

<分区>

我使用以下方式,在 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

关于c++ - 静态检测任何重载的 operator(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33111722/

相关文章:

c++ - 从时钟周期获取时间

c++ - 使用 C++11 异步时 Libusb 挂起

c++11 - 将最佳 uint8_t 位图转换为 8 x 32 位 SIMD "bool"向量

c++ - const char * 到 std::basic_iostream

C++ 信号量 (semi *lockfree*),我在哪里可以得到一个?

c++ - 检测 C++ 中的一个或两个补码架构?

c++ - 使用一元调整大小减小非默认可构造元素的容器大小

c++ - 将结构内的二维数组传递给另一个结构

c++ - 写入图像

c++ - 确定对象是否分配在静态内存块中(或如何避免数据竞争条件)