【问题标题】:Detecting presence of an arbitrary member检测任意成员的存在
【发布时间】:2015-10-13 17:44:44
【问题描述】:

使用void_t 可以很容易地编写一个模板来检测类型中是否存在特定成员:

#include <type_traits>

// This comes from cppreference
template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

// primary template handles types that have no ::aMember 
template< class T, class = void_t<> >
struct has_aMember : std::false_type { };

// specialization recognizes types that do have a ::aMember
template< class T >
struct has_aMember<T, void_t<decltype( T::aMember )>> : std::true_type { };

现在,如果我想检测是否存在其他成员,我必须复制粘贴检测器模板并将aMember 更改为otherMember

template< class T, class = void_t<> >
struct has_otherMember : std::false_type { };

template< class T >
struct has_otherMember<T, void_t<decltype( T::otherMember )>> : std::true_type { };

我想避免这种复制粘贴并将成员名称作为参数传递给更通用的检测模板版本:

template< class T, class member, class = void_t<> >
struct has_arbitrary_member : std::false_type { };

template< class T, class member >
struct has_arbitrary_member<T, void_t<decltype( T::member )>> : std::true_type { };

这样我就可以通过将类型和成员名称作为模板参数传递来使用这个has_arbitrary_member

 std::cout << has_arbitrary_member<MyType, aMember>();
 std::cout << has_arbitrary_member<MyType, otherMember>();

但是,根据我上面起草的定义,这将无法编译。有没有其他方法可以实现这样的功能?

【问题讨论】:

  • 你能做的最好的事情就是std::experimental::is_detected
  • “喜欢”是什么意思? above 的代码块like 这两行。你的硬性要求是什么,它们上面的代码块是如何不符合你的要求的?我可以在上面写一个更好的代码版本(比如is_detected),但如果这是你想要的,我就没有办法了。
  • @Yakk 我在问题的末尾添加了一句话,以更清楚地说明我的意图。当然 void_t 不是必需的,尽管我看到 is_detected 是使用 void_t 本身实现的。这有帮助吗?
  • @Rostislav:恕我直言,这仍然有点不清楚。您可以使用 T::myMember 获得 SFINAE,因此无论如何模板选择都应该起作用。您能否举例说明您希望代码的外观(不需要为每个数据成员检测器)?
  • @AndyG 这样更好吗?

标签: c++ templates c++11 c++14


【解决方案1】:

您尝试执行的操作通常是不可能的,因为您无法在 aMember 上禁止名称查找,除非您使用宏修改令牌流。因此,除非您当前 SFINAE 中,否则您永远无法避免使用不在范围内的名称,这将抑制错误。

这意味着您确实必须为每个名称编写单独的模板。

这是使用宏不是一个坏主意的情况之一,尽管这取决于您是否真的需要检查特定名称的成员,或者是否有更好的方法来实现您的目标。

【讨论】:

  • 这是一个理论上的好奇心引发的问题。感谢您的回答!
  • @Rostislav 对于它的价值,用字符串化做起来并不难
【解决方案2】:

不,您不能在不提及成员名称来自哪个类/结构的情况下将成员名称作为模板参数传递。

如果该类/结构没有该成员名称,则代码有错误。

现在,void_t&lt; decltype( &amp;MyType::some_member ) &gt; 要么是 void,要么是替换失败,具体取决于 some_member 是否存在。这通常可以解决不需要编译时布尔值的 SFINAE 问题。

如果您希望代码在某些类型没有有成员的情况下运行,可以通过仔细选择重载顺序或模板特化等来做到这一点。

不如has_arbitrary_member&lt;MyType, some_member&gt;强大。

template<class T>
using some_member_type = decltype( std::declval<T>().some_member );

是一个简单的特征,使用std::experimental::is_detected 你可以做到:

is_detected_v< some_member_type, T >

template<class T>
constexpr bool has_some_member_v = is_detected_v< some_member_type, T >;

其行为类似于has_arbitrary_member&lt;MyType, some_member&gt;。我发现这在实践中是最好的。

【讨论】:

  • 谢谢!我只是希望我错过了一些东西,在这种情况下有一种方法可以绕过复制粘贴或宏。但至少我学到了一些新东西——is_detected 的东西。只是一个小问题 - Library Fundamentals v2 是针对 c++17 的 TS 是否正确?
猜你喜欢
  • 2015-12-10
  • 2011-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多