在编译时检查 class 中的静态函数是否可用

Check if static function is available in class at compile time

我目前正在连接一个应用程序,该应用程序具有多个用于单一目的的实现。在运行时检查是否可以使用适当的实现或者是否使用回退。

为此,我希望所有实现都实现一个静态函数 static bool is_available()

由于静态函数不能在底层基础中抽象化class,是否有一些预处理器魔术可以让我在子方法中未静态实现时输出错误消息class?

您可以在编译时使用模板对此进行测试。 它是这样的(抱歉没有测试):

template<class Type_to_test, class Technical_Detail = void>
struct has_isAvilable : std::false_type {}

template<class Type_to_test>
struct has_isAvilable<Type_to_test, std::enable_if_t<
  std::is_same<bool,decltype(Type_to_test::is_available())>::value
> > : std::true_type {}

然后你可以在你的代码中使用:

static_assert(has_isAvilable<Implementation>::value,"Usefull error message");

其中 Implementation 是您要测试的 class。 查看 std::type_traits 以获取相关示例。

, you can define a trait using SFINAE 一样,在编译时检查 类:

的可用性
#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;

这意味着库的 C++17 和 constexpr 函数 is_available

#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


如果 C++17 不是一个选项,您可以 std::is_invocable_r 仅使用 C++14 功能实现。

如果 constexpr 静态成员函数不是您的库 类 的选项,您不能依赖 std::true_typestd::false_type,必须使用 运行 -时间结果收集:

#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

我会建议一个替代方案:标签调度:

template <typename T> struct Tag {};

struct Base { /**/ };
struct Child1 : Base { /**/ };
struct Child2 : Base { /**/ };

bool is_available(Tag<Base>) {/*..*/}
bool is_available(Tag<Child1>) {/*..*/}
bool is_available(Tag<Child2>) {/*..*/}

Tag "blocks" 继承,相反:

struct Base { static constexpr bool is_available() { return false; } };
struct Child1 : Base { static constexpr bool is_available() { return true; } };
struct Child2 : Base { /**/ };

static_assert(Base::is_available() == false);
static_assert(Child1::is_available() == true);
static_assert(Child2::is_available() == false); // Call Base::is_available()