如何测试方法是否为常量?

时间:2015-05-23 00:45:14

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

如何获得一个布尔值,指示已知方法是否具有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<decltype(&A::method)>::value但它不起作用,我可以理解为什么(void (*ptr)() const) != const void (*ptr)())。

4 个答案:

答案 0 :(得分:9)

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

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<const T>()进行冲洗并重复,以检查是否可以在const - 合格的左值上调用所述函数。我认为const &&成员函数没有好的用例,所以检测这个案例是否有意义是值得怀疑的。

请参阅当前Library Fundamentals 2 TS working draft了解如何实施is_detected

检查特定指向成员函数类型的指针是否指向具有特定 cv-qualifier-seq 的函数类型会更复杂。这需要每个 cv-qualifier-seq 的6个部分特化(constconst volatile是不同的 cv-qualifier-seq s),并且仍然可以处理重载的成员函数或成员函数模板。草绘这个想法:

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个部分专精。

答案 1 :(得分:8)

std::is_const<decltype(&A::method)>::value不起作用的原因是const成员函数不是const(成员函数)。它不是constconst int相同的顶级int

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

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

答案 2 :(得分:1)

创建类型特征以确定方法的一致性:

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;
};

答案 3 :(得分:0)

在C ++ 20中,由于concepts已被标准化,从而简化了检测习惯,因此事情变得容易得多。

现在我们需要写的就是这个约束:

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

ConstCallableMethod测试,假设_instance.has_method()是const引用类型,则表达式_instance的格式正确。

给出两个课程:

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

struct B {
    void method() { }
};

trueA)的约束为ConstCallableMethod<A>false的约束为B


如果您还想 测试method函数的返回类型为空,则可以像这样将->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