很多Boost的SFINAE助手都出现在带有C ++ 11的std库中,但has_dereference
似乎没有。除了这个功能,我已经设法从我的包中消除了Boost依赖,我想完全摆脱它,那么如何使用C ++ 11 std功能获得相同的效果呢?
答案 0 :(得分:6)
检查类是否具有某些没有外部依赖关系的函数的最简单方法通常是使用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:How does `void_t` work。
答案 1 :(得分:4)
这是一个整洁的小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
机制。你写了一个表达&#34;某些计算结果的特征&#34;从中我们可以得到&#34;该计算有效&#34;。
高度可移植的void_t
看起来像:
namespace details {
template<class...>struct voider{using type=void;};
}
template<class...Ts>
using void_t=typename voider<Ts...>::type;
在一行中执行它会破坏一些较旧的编译器,并且2行版本也很容易,也可能。
答案 2 :(得分:0)
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...>>;