29 votos

Detectar la existencia de un miembro privado

Quiero escribir un tipo de rasgo para comprobar si un cierto tipo tiene un miembro, member. Si member eran públicas, hay cualquier número de maneras de hacer esto (por ejemplo void_t), la más concisa de lo que es, probablemente, Yakk s can_apply (que podría ser llamado 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

Pero si el miembro fueron privado, este rasgo de la falla, ya que el acceso en member está mal formado (no somos amigos) y no hay diferenciación entre el mal formado debido a las razones y mal formado debido a esto-cosa-no-existen razones:

class D {
    int member;
};

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

Es allí una manera de escribir un miembro de corrector a través de todos los controles de acceso?

24voto

Columbo Puntos 11661

De hecho, hay un camino para los no-final de la no unión de tipos de clase - por ejemplo, como se emplea aquí:

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)){}>;

Demo. El truco es comprobar si la búsqueda en diferentes bases de clases producirá una ambigüedad. [clase.miembro.búsqueda]/2:

Nombre de miembro de búsqueda determina el significado de un nombre (identificador de expresión) en el ámbito de la clase (3.3.7). La búsqueda de nombres puede resultar en una ambigüedad, en el que caso de que el programa está mal formado. [...] La búsqueda del nombre se lleva a cabo antes de control de acceso (3.4, la Cláusula 11).

Tenga en cuenta que usted necesita para distinguir entre los nombres que denotan tipos y aquellos que denotan objetos/funciones/referencias/plantillas, como de búsqueda tiene en cuenta la construcción en la que el nombre fue utilizado.

4voto

Petr Puntos 4434

Puede crear otra clase MemberBase que tiene ese miembro , y luego la subclase las dos clases (la clase para comprobar T y BaseMember ) y tratar de obtener acceso al miembro de la subclase. Si T tiene un member miembro, entonces usted tendrá un problema de ambigüedad.

Código:

#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

Sin embargo, esto definitivamente huele un truco sucio para mí.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X