我目前正在为一个目的连接具有多个实现的应用程序。在运行时检查是否可以使用适当的实现或是否使用后备。
为此,我希望所有实现都实现一个静态函数static bool is_available()
。
由于不能在基础基类中使静态函数抽象化,因此如果子类中未静态实现该方法,是否存在一些预处理器魔术可以让我输出错误消息?
答案 0 :(得分:2)
与user9400869's answer一样,您可以使用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';
}
如果不能使用C ++ 17,则只能使用C ++ 14功能实现std::is_invocable_r
。
如果constexpr
静态成员函数不是库类的选项,则您不能依赖std::true_type
和std::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(); }
};
答案 1 :(得分:1)
您可以在编译时使用模板对此进行测试。 像这样(抱歉,未经测试):
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");
“实现”是您要测试的类。
看看std::type_traits
就是这样的例子。
答案 2 :(得分:0)
我建议使用另一种方法:标签分配:
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
“阻止”继承,与以下情况相反:
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()