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';
}
Full demo
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(); }
};
Full demo