检测任意成员的存在

时间:2015-10-13 17:44:44

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

使用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>();

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

2 个答案:

答案 0 :(得分:8)

除非您使用宏修改令牌流,否则您通常无法在aMember无法禁止名称查找。因此,除非您当前 SFINAE内部,否则您永远无法使用不在范围内的名称,这将抑制错误。

这意味着你真的必须为每个名字写一个单独的模板。

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

答案 1 :(得分:3)

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

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

现在,void_t< decltype( &MyType::some_member ) >void或替换失败,具体取决于some_member是否存在。通常,这解决了SFINAE问题,你不需要编译时bool。

如果希望代码在某些类型的情况下运行,可以通过仔细选择重载顺序或模板特化等来执行此操作。

它没有has_arbitrary_member<MyType, some_member>那么强大。

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<MyType, some_member>。我觉得这在实践中是最好的。