如何获得一个布尔值,指示已知方法是否具有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)()
)。
答案 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个部分特化(const
和const 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(成员函数)。它不是const
与const 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 { };
答案 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() { }
};
true
(A
)的约束为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)>