I am currently wiring an application that has several implementations for a single purpose. It is checked at runtime if the appropriate implementation can be used or if a fallback is used.
For that purpose I want all implementations to implement a static function static bool is_available()
.
As static functions cannot be made abstract in the underlying base class, is there some preprocessor magic that will allow me to output an error message if the method is not statically implemented in the child class?
In the same vein that user9400869's answer, you can define a trait using SFINAE to check, at compilation time, the availability of your classes:
#include <type_traits>
template<class LIB, class = void>
struct is_available
: std::false_type
{};
template<class LIB>
struct is_available<LIB, std::enable_if_t<std::is_invocable_r<bool, decltype(LIB::is_available)>::value>>
: std::integral_constant<bool, LIB::is_available()>
{};
template<class LIB>
constexpr bool is_available_v = is_available<LIB>::value;
This implies C++17 and constexpr
functions is_available
for the libs:
#include <iostream>
struct A {};
struct B { static constexpr bool is_available() { return false; } };
struct C { static constexpr bool is_available() { return true; } };
int main()
{
std::cout << is_available_v<A> // 0
<< is_available_v<B> // 0
<< is_available_v<C> // 1 :)
<< '\n';
}
If C++17 is not an option, you can implement std::is_invocable_r
using C++14 features only.
If constexpr
static member functions are not an option for your library classes, you cannot rely on std::true_type
and std::false_type
and must use run-time result gathering:
#include <type_traits>
template<class LIB, class = void>
struct is_available
{
static bool value() { return false; }
};
template<class LIB>
struct is_available<LIB, std::enable_if_t<std::is_invocable_r<bool, decltype(LIB::is_available)>::value>>
{
static bool value() { return LIB::is_available(); }
};