检查类是否具有函数(返回类型和常量选中)

Checking if a class has a function (return type and const checked)

本文关键字:常量 返回类型 是否 函数 检查      更新时间:2023-10-16

给定

class A {
public:
    bool foo(int) const {return true;}
};

我想要HasFooWithStringReturnTypeAndIsConst<A>::valueHasFooWithBoolReturnTypeAndIsNotConst<A>::value为假(HasFooWithBoolReturnTypeAndIsConst<A>::value已经返回 true,因此工作正常(。 这是我所拥有的:

#include <iostream>
#include <type_traits>
#include <string>
class A {
public:
    bool foo(int) const {return true;}
};
template <typename...> struct voider {using type = void;};
template <typename... Ts>
using void_t = typename voider<Ts...>::type;
template <typename T, typename = void_t<T>>
struct HasFooWithBoolReturnTypeAndIsNotConst : std::false_type {};
template <typename T>
struct HasFooWithBoolReturnTypeAndIsNotConst<T,
        void_t<decltype(std::declval<T&>().foo(std::declval<int>()))>> {
    using Foo = bool (T::*)(int);
    template <typename U> static std::true_type test (Foo*);
    template <typename U> static std::false_type test (...);
    static constexpr bool value = std::is_same<decltype(test<T>(nullptr)), std::true_type>::value;
};
template <typename T, typename = void_t<T>>
struct HasFooWithStringReturnTypeAndIsConst : std::false_type {};
template <typename T>
struct HasFooWithStringReturnTypeAndIsConst<T,
        void_t<decltype(std::declval<T&>().foo(std::declval<int>()))>> {
    using Foo = std::string (T::*)(int) const;
    template <typename U> static std::true_type test (Foo*);
    template <typename U> static std::false_type test (...);
    static constexpr bool value = std::is_same<decltype(test<T>(nullptr)), std::true_type>::value;
};
int main() {
    std::cout << HasFooWithStringReturnTypeAndIsConst<A>::value << 'n';  // true (should be false!)
    std::cout << HasFooWithBoolReturnTypeAndIsNotConst<A>::value << 'n';  // true (should be false!)
}

有人可以解释为什么他们返回true而不是false吗? 如何修复它们以使它们返回 false? A::foo(int)是一个返回布尔值的 const 函数,所以它们应该返回 false,不是吗?

您的支票适用于:

decltype(test<T>(nullptr))

两个重载是:

template <typename U> static std::true_type test(Foo*);
template <typename U> static std::false_type test(...);

这里没有任何地方你真正考虑&T::foo.您只是在检查是否可以将nullptr转换为某种任意指针类型。当然可以。这就是为什么它最终会变成 true_type .您要检查的是是否可以将&T::foo专门转换为该类型:

template <typename U> static std::true_type test (std::string (U::*)(int) const );
template <typename U> static std::false_type test (...);
static constexpr bool value = decltype(test<T>(&T::foo))::value;

请注意,在部分专业化中,您可以通过以下方式直接简单地完成这一切:

template <typename T>
struct HasFooWithStringReturnTypeAndIsConst<T,
            std::enable_if_t<
                std::is_same<std::string,
                             decltype(std::declval<const T&>().foo(0))
                             >::value
            >> : std::true_type { };

在这里,我们通过在const T&上调用它来检查foo()是否const,然后简单地检查它的返回类型是否为 std::string