【问题标题】:Checking if a class has a function (return type and const checked)检查一个类是否有一个函数(返回类型和 const 检查)
【发布时间】:2015-12-12 01:38:32
【问题描述】:

给定

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

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

#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?如何修复它们以使它们返回错误? A::foo(int) 是一个返回 bool 的 const 函数,所以它们应该返回 false,不是吗?

【问题讨论】:

    标签: c++ templates c++11 template-meta-programming


    【解决方案1】:

    您的支票用于:

    decltype(test<T>(nullptr))
    

    而这两个重载是:

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

    您实际上没有考虑&amp;T::foo。您只是在检查是否可以将 nullptr 转换为任意指针类型。当然,你可以。这就是它以true_type 结尾的原因。您要检查的是是否可以将 &amp;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&amp; 上调用它来检查foo() 是否为const,然后简单地检查其返回类型是否为std::string

    【讨论】:

    • @Barry 您的第二个解决方案有问题。 const T&amp;T&amp; 版本都将返回 true,而 T&amp; 版本不应该返回 true。这是一个演示:ideone.com/P6hD7D
    • @prestokeys 解决方案没有问题。我从未声称它会检查它是否不是 const。
    • 如何修改您的第二个解决方案,以便检查非常数?不过,您的第一个解决方案可以完成这项工作。
    • @prestokeys HasFooWithBoolReturnTypeAndIsNotConst 的特化继承自 !HasFooWithBoolReturnTypeAndIsConst 而不是 true_type
    • @Barry 好的,我认为你的最新想法很有效。我用A 和一个新类B 对其进行了测试,该类foo 不是const。我希望这就是你的意思:ideone.com/UqrjOv 至少输出是正确的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-15
    • 1970-01-01
    • 1970-01-01
    • 2023-04-02
    • 2023-03-25
    相关资源
    最近更新 更多