【问题标题】:How to test if a method is const?如何测试一个方法是否为 const?
【发布时间】:2015-08-05 03:05:53
【问题描述】:

如何获得一个布尔值来指示已知方法是否具有 const 限定符?

例如:

struct A {
    void method() const {}
};

struct B {
    void method() {}
};

bool testA = method_is_const<A::method>::value; // Should be true
bool testB = method_is_const<B::method>::value; // Should be false

type_traits 标头中,我找到了可以使用的is_const 测试,但我需要方法类型,但我不确定如何获得它。

我试过了:std::is_const&lt;decltype(&amp;A::method)&gt;::value,但它不起作用,我可以理解为什么(void (*ptr)() const) != const void (*ptr)())。

【问题讨论】:

  • 解决最后一部分,因为第一个是返回void的常量函数指针,第二个是返回const void的函数指针。
  • 另外,我将推测 is_const 正在捕获返回类型,而不是函数本身的 const 限定符。但是,我无法正确回答这个问题,因为我不确定如何让它按照您的意愿行事。
  • @William 感谢您的帮助。是的,我不知道如何检查 const 限定符 =/

标签: c++ templates c++11 typetraits


【解决方案1】:

检查是否可以在const-qualified 左值上调用成员函数要简单得多。

template<class T>
using const_lvalue_callable_foo_t = decltype(std::declval<const T&>().foo());

template<class T>
using has_const_lvalue_callable_foo = std::experimental::is_detected<const_lvalue_callable_foo_t, T>;

冲洗并重复,除了std::declval&lt;const T&gt;(),检查是否可以在const-qualified rvalue 上调用所述函数。我认为const &amp;&amp; 成员函数没有好的用例,所以检测这种情况是否有意义是值得怀疑的。

请查阅当前的Library Fundamentals 2 TS working draft,了解如何实现is_detected


检查一个特定的指向成员函数类型是否指向具有特定cv-qualifier-seq的函数类型要复杂得多。每个 cv-qualifier-seq 需要 6 个部分特化(constconst volatile 是不同的 cv-qualifier-seq),并且仍然无法处理重载成员函数或成员函数模板。构思草图:

template<class T> 
struct is_pointer_to_const_member_function : std::false_type {};

template<class R, class T, class... Args> 
struct is_pointer_to_const_member_function<R (T::*)(Args...) const> : std::true_type {};

template<class R, class T, class... Args> 
struct is_pointer_to_const_member_function<R (T::*)(Args...) const &> : std::true_type {};

template<class R, class T, class... Args> 
struct is_pointer_to_const_member_function<R (T::*)(Args...) const &&> : std::true_type {};

template<class R, class T, class... Args> 
struct is_pointer_to_const_member_function<R (T::*)(Args..., ...) const> : std::true_type {};

template<class R, class T, class... Args> 
struct is_pointer_to_const_member_function<R (T::*)(Args..., ...) const &> : std::true_type {};

template<class R, class T, class... Args> 
struct is_pointer_to_const_member_function<R (T::*)(Args..., ...) const &&> : std::true_type {};

如果您也希望 const volatile 也成为 true,请按照这些思路取消另外 6 个部分专业化。

【讨论】:

  • 请原谅我的无知,但是您引用的那个链接是什么?它是否包含已经在 C++X 标准中可用的官方扩展,还是对未来版本的提议?
  • @JanitoVaqueiroFerreiraFilho 这是提议的技术规范的工作草案。里面的东西很可能会进入下一个版本的 C++ 标准。至于is_detected,是两周前投票的,所以可能还没有实现,但是TS提供了它的完整实现,所以你可以拿来用它。
  • 您的实现忽略了只能在右值上调用的函数,不是吗?
  • @Columbo 当然,但你真的在乎吗?我认为const &amp;&amp; 成员函数没有好的用例。
  • @T.C.加上volatile,不是吗?
【解决方案2】:

std::is_const&lt;decltype(&amp;A::method)&gt;::value 不起作用的原因是 const 成员函数不是 const(成员函数)。它不像const intint 那样是顶级的const

我们可以做的是使用 void_t 的类型特征来测试我们是否可以在 const T 上调用 method

template <typename... >
using void_t = void;

template <typename T, typename = void>
struct is_const_callable_method : std::false_type { };

template <typename T>
struct is_const_callable_method<T, void_t<
    decltype(std::declval<const T&>().method())
    > > : std::true_type { };

Demo

【讨论】:

    【解决方案3】:

    在 C++20 中,事情变得容易多了,因为 concepts 已经标准化,包含了检测习语。

    现在我们只需要编写这个约束:

    template<class T>
    concept ConstCallableMethod = requires(const T& _instance) {
        { _instance.method() }
    };
    

    ConstCallableMethod 测试表达式_instance.has_method() 的格式是否正确,因为_instance 是一个常量引用类型。

    鉴于你的两个类:

    struct A {
        void method() const { }
    };
    
    struct B {
        void method() { }
    };
    

    对于A (ConstCallableMethod&lt;A&gt;) 的约束将是true,对于B 的约束将是false


    如果您希望测试method函数的返回类型是否为void,您可以像这样将-&gt;void添加到约束中:

    template<class T>
    concept ConstCallableMethodReturnsVoid = requires(const T& _instance) {
        { _instance.method() } -> void
    };
    

    如果您希望更通用一点,可以将成员函数指针传递给该概念并测试是否可以使用 const 实例调用该函数指针(尽管当您有重载):

    template<class T, class MemberF>
    concept ConstCallableMemberReturnsVoid = requires(const T& _instance, MemberF _member_function) {
        { (_instance.*_member_function)() } -> void
    };
    

    你可以这样称呼它:

    ConstCallableMemberReturnsVoid<A, decltype(&A::method)>
    

    这允许其他一些理论类,如 C,它有一个 const 方法,但它没有命名为 method

    struct C
    {
        void foobar() const{}
    };
    

    我们可以用同样的概念来测试:

    ConstCallableMemberReturnsVoid<C, decltype(&C::foobar)>
    

    Live Demo

    【讨论】:

      【解决方案4】:

      创建一个类型特征来确定方法的 const-ness:

      template<typename method_t>
      struct is_const_method;
      
      template<typename CClass, typename ReturnType, typename ...ArgType>
      struct is_const_method< ReturnType (CClass::*)(ArgType...)>{
          static constexpr bool value = false;
      };
      
      template<typename CClass, typename ReturnType, typename ...ArgType>
      struct is_const_method< ReturnType (CClass::*)(ArgType) const>{
          static constexpr bool value = true;
      };
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-02-11
        • 2020-10-25
        • 1970-01-01
        • 1970-01-01
        • 2011-07-03
        • 1970-01-01
        • 1970-01-01
        • 2021-08-05
        相关资源
        最近更新 更多