27 votes

Détecter l'existence d'un membre privé

Je veux écrire un type de trait pour vérifier si un type a un membre de l' member. Si member ont été publique, il ya un certain nombre de façons de le faire (par exemple, void_t), la plus concise de ce qui est probablement Yakk de l' can_apply (qui pourrait éventuellement être appelé 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

Mais si le membre était privé, ce trait de caractère ne parvient pas, depuis l'accès sur l' member est mal formé (nous ne sommes pas des amis) et il n'y a pas de différenciation entre les mauvais formé en raison de l'accès raisons et mal formé pour cette raison-chose-ne pas exister raisons:

class D {
    int member;
};

static_assert(has_member<D>{}, "!"); // error

Est-il possible d'écrire un tel membre vérificateur à travers tous les contrôles d'accès?

21voto

Columbo Points 11661

Il est en effet un moyen pour les non-final-non-union types de classe - par exemple, tel qu'employé ici:

namespace detail {
    struct P {int member;};
    template <typename U>
    struct test_for_member : U, P
    {
        template <typename T=test_for_member, typename=decltype(&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)){}>;

La démo. Le truc, c'est de vérifier si la recherche dans les différentes classes de base donnera une ambiguïté. [classe.membre.recherche]/2:

Membre de recherche de nom détermine le sens d'un nom (id-expression) dans un contexte de classe (3.3.7). La recherche d'un nom peut entraîner une ambiguïté, dans auquel cas le programme est mal formé. [...] La recherche du nom de lieu avant de contrôle d'accès (3.4, article 11).

Notez que vous avez besoin de distinguer entre les noms désignant des types et ceux désignant des objets/fonctions/références/modèles de recherche prend en compte la construction dans laquelle le nom a été utilisé.

4voto

Petr Points 4434

Vous pouvez créer une autre classe MemberBase qui ne dispose que membre, puis sous - classe les deux classes (la classe pour vérifier T et BaseMember ) et essayer d'accéder au membre de la sous-classe. Si T également un membre member , vous obtiendrez un problème d'ambiguïté.

Code:

 #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
 

Cependant, cela sent vraiment comme un hack sale pour moi.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X