2012-01-24 18 views
14

Me pregunto si si pruebo a algún miembro de una clase y el miembro es privado, ¿qué responderá sfinae? ¿Se equivocará o dirá que está bien o se equivocará de la misma manera?¿Puede SFINAE detectar violaciones de acceso privado?

+3

... ¿realmente lo has probado? – Mehrdad

+5

No, yo no lo probé. No sé de una implementación completamente conforme. –

+1

@Mehrdad: pero ¿cómo interpretar el resultado de la prueba? Sabrá cómo lo interpreta * el compilador *, pero ¿cómo sabrá si el compilador cumple con las normas? –

Respuesta

11

Sí.

EDIT: C++ 11 cotización estándar de §14.8.2 [temp.deduct]

8/ Si un cambio da como resultado un tipo o expresión no válida, el tipo de deducción falla . Un tipo o expresión inválida es aquella que estaría mal formada si se escribiera utilizando los argumentos sustituidos. [Nota: la verificación de acceso se realiza como parte del proceso de sustitución. nota -fin]

Esto me sugiere que private puede desencadenar un error SFINAE. Leyendo en:

Solo los tipos y expresiones no válidos en el contexto inmediato del tipo de función y sus tipos de parámetros de plantilla pueden dar como resultado un error de deducción. [Nota: la evaluación de los tipos y expresiones sustituidos puede producir efectos secundarios tales como la instanciación de especializaciones de plantilla de clase y/o especializaciones de plantilla de función, la generación de funciones implícitamente definidas, etc. Tales efectos secundarios no están en el “contexto inmediato” y puede resultar en el programa fue la nota mala formed.-final]

el "contexto inmediato" no es tan claro para mí ... pero no contradice mi punto :)

final de EDIT

Por lo tanto, me parece que va a error a cabo de una manera SFINAE, esto se ve confirmado por este extracto de Clang:

// clang/Basic/DiagnosticIDs.h:185-209 

    /// \brief Enumeration describing how the the emission of a diagnostic should 
    /// be treated when it occurs during C++ template argument deduction. 
    enum SFINAEResponse { 
    /// \brief The diagnostic should not be reported, but it should cause 
    /// template argument deduction to fail. 
    /// 
    /// The vast majority of errors that occur during template argument 
    /// deduction fall into this category. 
    SFINAE_SubstitutionFailure, 

    /// \brief The diagnostic should be suppressed entirely. 
    /// 
    /// Warnings generally fall into this category. 
    SFINAE_Suppress, 

    /// \brief The diagnostic should be reported. 
    /// 
    /// The diagnostic should be reported. Various fatal errors (e.g., 
    /// template instantiation depth exceeded) fall into this category. 
    SFINAE_Report, 

    /// \brief The diagnostic is an access-control diagnostic, which will be 
    /// substitution failures in some contexts and reported in others. 
    SFINAE_AccessControl 
    }; 

Hay casos especiales en materia de control de acceso en el caso de SFINAE.

2

No lo creo.

11/4 "control miembros de acceso" (C++ 03):

La interpretación de un constructo dado se establece sin tener en cuenta al control de acceso. Si la interpretación establecida hace uso de nombres de los miembros o clases base inaccesible, está mal formada la construcción .

Así que la resolución de sobrecarga se produce primero, luego se aplica el control de acceso.

+0

Hm, ¿pensé que se produciría sfinae si la construcción de la plantilla estaría bien informada? –

+2

En realidad, parece que hay una disposición especial en ** [temp.deduct] ** para la sustitución. Ver §14.8.2/8 en mi respuesta. –

5

No. Estoy en el camino y no tengo un estándar para citarme, pero sfinae toma posiciones en la fase de compilación donde el compilador comprueba si el nombre existe, y en un control de acceso de fase posterior toma lugar.

Esto es similar a la resolución de sobrecarga, donde se consideran todos los nombres, y una coincidencia que es privada es mejor, pero no se compilará, aunque existe otra coincidencia que sería "aceptable" pero no privada.

Adición:

tema Core 1170 dice: comprobar

1170 Acceso plantilla durante la deducción argumento
Sección: 14.8.2 [temp.deduct]
Estado: FDIS Peticionario: Adamczyk Fecha: 2010-08-03

[Votó en el WP en la reunión de marzo de 2011.]

De acuerdo con 14.8.2 [temp.deduct] párrafo 8,

comprobación acceso no se realiza como parte del proceso de sustitución. En consecuencia, cuando la deducción tiene éxito, aún se puede producir un error de acceso cuando se crea una instancia de la función.

Esto imita la forma en que se realiza la verificación de acceso en la resolución de sobrecarga. Sin embargo, la experiencia ha demostrado que esta exención de los errores de acceso de la falla de deducción complica significativamente la biblioteca estándar, por lo que esta regla debe modificarse.

propuesta de resolución (enero de 2011):

Cambio 14.8.2 [temp.deduct] párrafo 8 de la siguiente manera:

Si un cambio da como resultado un tipo o expresión no válida, el tipo de deducción falla . Un tipo o expresión no válida sería mal formado si se escribe utilizando los argumentos sustituidos. [Nota: la verificación de acceso no se realiza como parte del proceso de sustitución.-finalizar] En consecuencia, cuando la deducción tiene éxito, un error de acceso todavía podría cuando se crea una instancia de la función. Sólo los tipos válidos ...

Así que mi interpretación es que esto es imposible en C++ 03, pero C++ 11 lo hizo posible.

1

Aquí hay un ejemplo que implementa is_comparable y maneja un operador potencialmente privado ==. g ++ - 4.7 choques en esto, pero g ++ - 4.8 y clang ++ 3.4 lo manejan correctamente en el modo C++ 11.

#include <iostream> 
#include <utility> 
// is_comparable trait 
template<class T> 
class is_comparable { 
    template<typename U> static char (&check (int))[1 + sizeof (decltype (
    std::declval<U>() == std::declval<U>() // trait check 
))]; 
    template<typename> static char (&check (...))[1]; 
public: 
    static constexpr const bool value = sizeof (check<T> (0)) != 1; 
}; 
// tests 
class Diff1 {};   // non-comparable 
class Diff2 {   // non-comprable, since member is private 
    bool operator== (const Diff2&); 
}; 
struct EqM { bool operator== (EqM); }; // comparable 
struct EqG {};       // comparable 
bool operator== (const EqG&, const EqG&); 
int 
main() 
{ 
    std::cout << "is_comparable:"; 
    std::cout << " void=" << is_comparable<void>::value; 
    std::cout << " Diff1=" << is_comparable<Diff1>::value; 
    std::cout << " Diff2=" << is_comparable<Diff2>::value; 
    std::cout << " int=" << is_comparable<int>::value; 
    std::cout << " EqM=" << is_comparable<EqM>::value; 
    std::cout << " EqG=" << is_comparable<EqG>::value; 
    std::cout << "\n"; 
    return 0; 
} 
// $ clang++ is_comparable.cc -std=c++11 && ./a.out 
// is_comparable: void=0 Diff1=0 Diff2=0 int=1 EqM=1 EqG=1 
Cuestiones relacionadas