相当于Boost has_dereference的C++11 std

C++11 std equivalent of Boost has_dereference

本文关键字:C++11 std dereference Boost has 相当于      更新时间:2023-10-16

Boost的许多SFINAE助手已经出现在C++11的std库中,但has_dereference似乎没有。除了这个功能,我已经设法从我的包中消除了Boost依赖,我想完全消除它,那么如何最好地使用C++11 std功能来获得同样的效果呢?

检查类是否具有没有外部依赖项的函数的最简单方法通常是使用void_t习惯用法。

// Define this once in your project somewhere accessible
template <class ... T>
using void_t = void;

那么诀窍总是一样的;定义一个从std::false_type:继承的类模板

template <class T, class = void>
struct has_dereference : std::false_type {};

这是"回退"类模板。现在,我们将定义一个专门化,只有当类型具有我们想要的属性时才有效:

template <class T>
struct has_dereference<T, void_t<decltype(*std::declval<T>())>> : std::true_type {};

要使用,只需执行:

bool x = has_dereference<int*>::value;
bool y = has_dereference<int>::value;

等等。

我要补充的是,从技术上讲,operator*实际上是一个函数族;操作员既可以是CV合格的,也可以是值类别合格的。无论何时对类型执行检测,实际上都是在该族中执行检测。我不会详细介绍它,因为它在实践中很少遇到(operator*很少有值类别限定,运算符几乎总是有const版本,volatile很少出现),但值得注意的是,以防您看到令人惊讶的东西。

这项技术值得了解,尤其是当你在没有Boost或Hana等依赖关系的情况下进行元编程时。你可以在这里阅读更多关于void_t的信息:"void_t"是如何工作的。

这是一个简洁的小SFINAE特性写作助手。它使用std::void_t,如果你没有它,你可以重新实现

namespace details {
  template<template<class...>class Z, class v, class...Ts>
  struct can_apply:std::false_type{};
  template<template<class...>class Z, class...Ts>
  struct can_apply<Z, std::void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply=typename details::can_apply<Z, void, Ts...>::type;

一旦你有了这些,你的问题就很容易了。

template<class T>
using deref_result = decltype(*std::declval<T>());
template<class T>
using can_deref = can_apply<deref_result, T>;

这里的想法是隐藏std::void_t机器。你写了一个特征来表达"某个计算的结果",从中我们可以得到"该计算有效吗"。

一个高度便携的void_t看起来像:

namespace details {
  template<class...>struct voider{using type=void;};
}
template<class...Ts>
using void_t=typename voider<Ts...>::type;

在一行中完成这项操作会破坏一些较旧的编译器,而两行版本也很容易。

Yakk的修改版本:

template <class...> struct pack {};
namespace detail {
    template<template <class...> class Z, class Pack, class = void>
    struct can_apply_impl : std::false_type {};
    template<template<class...>class Z, class...Ts>
    struct can_apply_impl<Z, pack<Ts...>, std::void_t<Z<Ts...>> > : std::true_type {};
}
template<template<class...>class Z, class...Ts>
using can_apply = detail::can_apply_impl<Z, pack<Ts...>>;

演示