2012-01-24 9 views
14

Mi chiedo se se provo per un membro di una classe e il membro è privato cosa risponderà sfinae? Uscirà un errore o dirà ok o uscirà fuori in modo sfinae?È possibile che SFINAE rilevi violazioni di accesso private?

+3

... l'hai provato? – Mehrdad

+5

No, non l'ho provato. non so di un'implementazione completamente conforme. –

+1

@ Mehrdad: ma come interpretare l'output del test? Saprai come il * compilatore * lo interpreta, ma come saprai se il compilatore è conforme allo standard? –

risposta

11

Sì.

EDIT: C++ 11 citazione Standard da §14.8.2 [temp.deduct]

8/ Se una sostituzione si traduce in un tipo o di un'espressione non valida, tipo detrazione fallisce . Un tipo o un'espressione non valida è uno che sarebbe mal formato se scritto usando gli argomenti sostituiti. [Nota: il controllo dell'accesso viene eseguito come parte del processo di sostituzione. Nota -end]

Questo mi fa pensare che private può innescare un errore SFINAE. Lettura su:

Solo tipi ed espressioni non validi nel contesto immediato del tipo di funzione e dei relativi tipi di parametri del modello possono causare un errore di deduzione. [Nota: la valutazione dei tipi e delle espressioni sostituite può provocare effetti collaterali come l'istanziazione delle specializzazioni del modello di classe e/o le specializzazioni del modello di funzione, la generazione di funzioni implicitamente definite, ecc. Tali effetti collaterali non sono nel “contesto immediato” e può comportare il programma essendo nota mal formed.-end]

il "contesto immediato" non è così chiaro per me ... ma non in contraddizione con il mio punto :)

fine dell'EDIT

Quindi mi sembra che sarà errore fuori in modo SFINAE, ciò è ulteriormente confermato da questo estratto da 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 
    }; 

Ci sono casi particolari in materia di controllo di accesso in caso di SFINAE.

2

Non credo.

11/4 "controllo Stati accesso" (C++ 03):

L'interpretazione di un dato costrutto è stabilito senza riguardo al controllo degli accessi. Se l'interpretazione stabilita fa uso di nomi di membri o classi di base inaccessibili , il costrutto è non formato.

Quindi la risoluzione di sovraccarico si verifica prima, quindi viene applicato il controllo di accesso.

+0

Hm ho pensato che sfinae succedesse se il costrutto del template fosse stato deformato? –

+2

In realtà, sembra che ci sia una disposizione speciale in ** [temp.deduct] ** per la sostituzione. Vedi §14.8.2/8 nella mia risposta. –

5

No. Sono in viaggio e non ho uno standard da citare con me, ma sfinae si svolge nella fase di compilazione in cui il compilatore verifica se il nome esiste del tutto e in una fase successiva di controllo di accesso ha luogo.

Questo è simile alla risoluzione di sovraccarico, in cui vengono considerati tutti i nomi e una corrispondenza privata è migliore, ma non verrà compilata, sebbene vi sia un'altra corrispondenza che sarebbe "ok" ma non privata.

Aggiunta:

Nucleo problema 1170 dice:

1170 Accesso verifica durante il modello detrazione argomento
Sezione: 14.8.2 [temp.deduct]
Stato: FDIS Inviato: Adamczyk Data: 2010-08-03

[Votato nel WP alla riunione di marzo 2011.]

Secondo 14.8.2 [temp.deduct] comma 8,

controllo di accesso non è fatto come parte del processo di sostituzione. Di conseguenza, quando la deduzione ha esito positivo, un errore di accesso può ancora produrre quando la funzione viene istanziata.

Questo simula il modo in cui il controllo dell'accesso viene eseguito in risoluzione di sovraccarico. Tuttavia, l'esperienza ha dimostrato che questa esenzione dagli errori di accesso dall'errore di deduzione complica notevolmente la libreria Standard, , quindi questa regola deve essere modificata.

Proposta di delibera (gennaio 2011):

Change 14.8.2 [temp.deduct] paragrafo 8 come segue:

Se una sostituzione si traduce in un tipo o di un'espressione non valida, tipo detrazione non riesce . Un tipo o un'espressione non valida è uno che sarebbe malformato se scritto utilizzando gli argomenti sostituiti. [Nota: il controllo dell'accesso non viene eseguito come parte del processo di sostituzione.-end note] Di conseguenza, quando la detrazione ha esito positivo, un errore di accesso potrebbe ancora risultato quando la funzione viene istanziata. Solo i tipi di invalidi ...

Così la mia interpretazione è che questo è impossibile in C++ 03, ma C++ 11 ha reso possibile.

1

Ecco un esempio che implementa is_comparable e gestisce un operatore potenzialmente privato ==. g ++ - 4.7 induttanze su questo, ma g ++ - 4.8 e clang ++ 3.4 lo gestiscono correttamente in modalità 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 
Problemi correlati