Bar*_*rry 30 c++ templates type-traits c++11 c++14
我想写一个类型特征来检查某个类型是否有成员member
.如果member
是公开的,有很多方法可以做到这一点(例如void_t
),其中最简洁的可能是Yakkcan_apply
(最终可以调用std::is_detected
):
struct C {
int member;
};
template <typename T>
using member_type = decltype(&T::member);
template <typename T>
using has_member = can_apply<member_type, T>;
static_assert(has_member<C>{}, "!"); // OK
Run Code Online (Sandbox Code Playgroud)
但如果该成员是私人的,那么这种特性就会失败,因为访问权限member
是不正常的(我们不是朋友),并且由于访问原因而形成不良与由于这种事情导致的不良形式之间没有区别.存在的原因:
class D {
int member;
};
static_assert(has_member<D>{}, "!"); // error
Run Code Online (Sandbox Code Playgroud)
有没有办法在所有访问控制中编写这样的成员检查程序?
Col*_*mbo 25
对于非最终的非联合类类型确实有一种方法:
namespace detail {
struct P {typedef int member;};
template <typename U>
struct test_for_member : U, P
{
template <typename T=test_for_member, typename = typename T::member>
static std::false_type test(int);
static std::true_type test(float);
};
}
template <typename T>
using test_for_member =
std::integral_constant<bool, decltype(detail::test_for_member<T>::test(0)){}>;
Run Code Online (Sandbox Code Playgroud)
演示.诀窍是检查查找不同的基类是否会产生歧义.[class.member.lookup]/2:
成员名称查找确定类范围(3.3.7)中名称(id-expression)的含义.名称查找可能导致歧义,在这种情况下程序是不正确的.[...]名称查找在访问控制之前进行(3.4,第11条).
请注意,GCC查找被破坏,因为它忽略了typename-specifier中查找的非类型名称.
您可以创建另一个类MemberBase
是确实有该成员,然后继承两个类(类检查T
和BaseMember
),并尝试访问该子类的成员。如果T
也有member
成员,那么您将遇到歧义问题。
码:
#include <type_traits>
// Yakk's can_apply
template<class...>struct voider{using type=void;};
template<class...Ts>using void_t=typename voider<Ts...>::type;
template<class...>struct types{using type=types;};
namespace details {
template<template<class...>class Z, class types, class=void>
struct can_apply : std::false_type {};
template<template<class...>class Z, class...Ts>
struct can_apply< Z, types<Ts...>, void_t< Z<Ts...> > >:
std::true_type
{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,types<Ts...>>;
// Main code
class MemberBase {
public:
int member;
};
template<class ToCheck>
class MemberCheck: public ToCheck, public MemberBase {
};
template <typename T>
using member_type = decltype(&T::member);
template <typename T>
using hasnot_member = can_apply<member_type, MemberCheck<T>>;
template <typename T>
using static_not = std::integral_constant<bool, !T::value>;
template <typename T>
using has_member = static_not<hasnot_member<T>>;
// Tests
class A {
int member;
};
class Ap {
public:
int member;
};
class B {
float member;
};
class C {
int member();
};
class D {
};
static_assert(has_member<A>{}, "!"); // ok
static_assert(has_member<Ap>{}, "!"); // ok
static_assert(has_member<B>{}, "!"); // ok
static_assert(has_member<C>{}, "!"); // ok
static_assert(has_member<D>{}, "!"); // fail
Run Code Online (Sandbox Code Playgroud)
但是,这对我来说绝对是个肮脏的骇客。