检查一个类是否具有给定签名的成员函数

新手上路,请多包涵

我要求一个模板技巧来检测一个类是否具有给定签名的特定成员函数。

这个问题类似于这里引用的问题 http://www.gotw.ca/gotw/071.htm 但不一样:在 Sutter 的书中,他回答了一个类 C 必须提供一个成员函数的问题一个特定的签名,否则程序将无法编译。在我的问题中,如果一个类具有该功能,我需要做一些事情,否则做“其他事情”。

boost::serialization 也面临类似的问题,但我不喜欢他们采用的解决方案:一个模板函数默认调用具有特定签名的自由函数(您必须定义),除非您定义特定的成员函数(在他们的情况下,“序列化”采用给定类型的 2 个参数)具有特定签名,否则会发生编译错误。那就是实现侵入式和非侵入式序列化。

我不喜欢这个解决方案有两个原因:

  1. 为了非侵入性,您必须覆盖 boost::serialization 命名空间中的全局“序列化”函数,因此您可以在您的客户代码中打开命名空间提升和命名空间序列化!
  2. 解决这个混乱的堆栈是 10 到 12 个函数调用。

我需要为没有该成员函数的类定义自定义行为,并且我的实体位于不同的命名空间中(并且我不想在另一个命名空间中覆盖在一个命名空间中定义的全局函数)

你能给我一个提示来解决这个难题吗?

原文由 ugasoft 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 386
2 个回答

我不确定我是否理解正确,但您可以利用 SFINAE 在编译时检测函数的存在。我的代码中的示例(测试类是否具有成员函数 size_t used_memory() const)。

 template<typename T>
struct HasUsedMemoryMethod
{
    template<typename U, size_t (U::*)() const> struct SFINAE {};
    template<typename U> static char Test(SFINAE<U, &U::used_memory>*);
    template<typename U> static int Test(...);
    static const bool Has = sizeof(Test<T>(0)) == sizeof(char);
};

template<typename TMap>
void ReportMemUsage(const TMap& m, std::true_type)
{
        // We may call used_memory() on m here.
}
template<typename TMap>
void ReportMemUsage(const TMap&, std::false_type)
{
}
template<typename TMap>
void ReportMemUsage(const TMap& m)
{
    ReportMemUsage(m,
        std::integral_constant<bool, HasUsedMemoryMethod<TMap>::Has>());
}

原文由 yrp 发布,翻译遵循 CC BY-SA 3.0 许可协议

使用 c++ 20,这变得更加简单。假设我们要测试一个类 T 是否有一个成员函数 void T::resize(typename T::size_type) 。比如 std::vector<U> 就有这样一个成员函数。然后,

 template<typename T>
concept has_resize_member_func = requires {
    typename T::size_type;
    { std::declval<T>().resize(std::declval<typename T::size_type>()) } -> std::same_as<void>;
};

用法是

static_assert(has_resize_member_func<std::string>, "");
static_assert(has_resize_member_func<int> == false, "");

原文由 Peter Rindal 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题