How can I get a boolean value indicating if a known method has the const qualifier or not?
For example:
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
In the type_traits
header I found an is_const
test I could use, but I need the method type, and I'm unsure how to obtain that.
I tried: std::is_const<decltype(&A::method)>::value
but it doesn't work, and I can understand why (void (*ptr)() const) != const void (*ptr)()
).
In C++20, things get a lot easier because concepts have been standardized, which subsumes the detection idiom.
Now all we need to write is this constraint:
template<class T>
concept ConstCallableMethod = requires(const T& _instance) {
{ _instance.method() }
};
ConstCallableMethod
tests that the expression _instance.has_method()
is well formed given that _instance
is a const-reference type.
Given your two classes:
struct A {
void method() const { }
};
struct B {
void method() { }
};
The constraint will be true
for A
(ConstCallableMethod<A>
) and false
for B
.
If you wish to also test that the return type of the method
function is void, you can add ->void
to the constraint like so:
template<class T>
concept ConstCallableMethodReturnsVoid = requires(const T& _instance) {
{ _instance.method() } -> void
};
If you wish to be a little more generic, you can pass in a member function pointer to the concept and test if that function pointer can be called with a const
instance (although this gets a little less useful when you have overloads):
template<class T, class MemberF>
concept ConstCallableMemberReturnsVoid = requires(const T& _instance, MemberF _member_function) {
{ (_instance.*_member_function)() } -> void
};
You'd call it like so:
ConstCallableMemberReturnsVoid<A, decltype(&A::method)>
This allows for some other theoretical class like C
, that has a const method, but it's not named method
:
struct C
{
void foobar() const{}
};
And we can use the same concept to test:
ConstCallableMemberReturnsVoid<C, decltype(&C::foobar)>
It is a lot simpler to check whether a member function can be called on a const
-qualified lvalue.
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>;
Rinse and repeat, except with std::declval<const T>()
, to check if said function can be called on a const
-qualified rvalue. I can think of no good use cases for const &&
member functions, so whether there's a point in detecting this case is questionable.
Consult the current Library Fundamentals 2 TS working draft on how to implement is_detected
.
It is a lot more convoluted to check whether a particular pointer-to-member-function type points to a function type with a particular cv-qualifier-seq. That requires 6 partial specializations per cv-qualifier-seq (const
and const volatile
are different cv-qualifier-seqs), and still can't handle overloaded member functions or member function templates. Sketching the idea:
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 {};
If you want const volatile
to be true
too, stamp out another 6 partial specializations along these lines.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With