There are a number of answered questions about checking whether a member function exists: for example, Is it possible to write a template to check for a function's exis
// use std::void_t in C++... 17 I think? ... instead of this:
templatestruct void_type { using type = void; };
templateusing void_t = typename void_type::type;
template
using hello_world_ify = decltype(
std::declval().helloworld( std::declval()... )
);
template
struct has_helloworld:std::false_type{};
template
struct has_helloworld
>
>:std::true_type{};
template
struct has_helloworld::value &&
std::is_convertible<
hello_world_ify,
R
>::value
>::type
>:std::true_type{};
live example
I'd put the above in a details
namespace, and then expose a template
so someone doesn't pass a type in place of the defaulted void
.
We use SFINAE to detect if we can invoke T.helloworld(Args...)
. If the passed in signature is void(blah)
, we just detect if the call can occur -- if not, we test that the return type of T.helloworld(Args...)
can be converted into the return type of the signature.
MSVC has significant issues doing SFINAE with decltype
, so the above may not work in MSVC.
Note that has_helloworld
corresponds to passing in an rvalue T
, invoking helloworld
in that rvalue context passing it rvalue Args...
. To make the values lvalues, add &
. To make them const lvalues, use const&
on the types. However, this should mostly only matter in some corner cases.
For the more general case, there is no way to detect the existence of an overridden method without having a sample signature to match.
The above can be adapted to handle exact signature matches.
Amusingly, if there is a signature conflict (ie, an error would occur in the immediate context of the call), it acts as if there is no such method.
As it relies on SFINAE, errors in the non-immediate context do not trigger failure.