2012-01-24 5 views
14

Интересно, если я проверяю какой-то член класса, а член является частным, что ответит sfinae? Будет ли это ошибка, или она скажет «ОК», или это будет ошибка в режиме sfinae?Может ли SFINAE обнаруживать нарушения частного доступа?

+3

... Вы действительно протестировали его? – Mehrdad

+5

Нет, я не тестировал его. Я не знаю об абсолютно соответствующей реализации. –

+1

@Mehrdad: но как интерпретировать выход теста? Вы узнаете, как интерпретирует его * компилятор *, но как вы узнаете, соответствует ли компилятор стандартным? –

ответ

11

Да.

РЕДАКТИРОВАТЬ: C++ 11 Стандартной цитата из §14.8.2 [temp.deduct]

8/ Если подмена приводит к недопустимому типу или выражение, типа вычет терпит неудачу , Недопустимый тип или выражение - это те, которые были бы плохо сформированы, если они были написаны с использованием замещенных аргументов. [Примечание: проверка доступа выполняется как часть процесса замещения. -end примечание]

Это наводит меня на мысль, что private может вызвать ошибку SFINAE. Чтение:

Только недопустимые типы и выражения в непосредственном контексте типа функции и ее типов параметров шаблона могут приводить к срыву дедукции. [Примечание. Оценки замещенных типов и выражений могут приводить к возникновению побочных эффектов, таких как создание специализированных специализированных шаблонов классов и/или функций, генерация неявно определенных функций и т. Д. Такие побочные эффекты отсутствуют в «непосредственный контекст» и может привести к программе болея-formed. конец примечания]

«непосредственный контекст» не очень понятно для меня ... но это не противоречит моей точке :)

конец EDIT

Так что, мне кажется, что он выдаст ошибку в пути SFINAE, это подтверждается еще и этот отрывок из 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 
    }; 

Существуют особые случаи в отношении контроля доступа в случае SFINAE.

2

Я так не считаю.

11/4 "Контроль доступа Член" (C++ 03):

интерпретация данной конструкции устанавливается без учета контроля доступа. Если установленная интерпретация использует недоступные имена членов или базовые классы, то конструкция плохо сформирована.

Так сначала возникает разрешение перегрузки, затем применяется контроль доступа.

+0

Хм я думал, что sfinae происходит, если шаблонная конструкция будет неформальной? –

+2

На самом деле, кажется, что существует специальное положение в ** [temp.deduct] ** для подстановки. См. §14.8.2/8 в моем ответе. –

5

Нет. Я нахожусь в дороге и не имею стандарта, чтобы процитировать со мной, но sfinae занимает места в фазе компиляции, где компилятор проверяет, существует ли это имя вообще, и в более позднем управлении доступом к фазе происходит.

Это похоже на разрешение перегрузки, где рассматриваются все имена, а совпадение является частным лучше, но не будет компилироваться, хотя есть и другое совпадение, которое было бы «нормально», но не закрыто.

Дополнение

Основная проблема 1170 говорит: проверка

1170 Доступ во время аргумента шаблона дедукции
Раздел: 14.8.2 [temp.deduct]
Статус: FDIS Отправитель: Адамчик Дата: 2010-08-03

[Проголосовал за WP на совещании в марте 2011 года.]

В соответствии с 14.8.2 [temp.deduct] пунктом 8,

проверка доступа не выполняются как часть процесса замещения. Следовательно, когда дедукция завершается успешно, ошибка при доступе может быть вызвана при создании экземпляра функции.

Это подражает способу проверки доступа при разрешении перегрузки. Однако опыт показывает, что это исключение ошибок доступа от дедукционного отказа значительно усложняет библиотеку Standard, , поэтому это правило должно быть изменено.

Предлагаемая резолюция (январь, 2011):

Изменение 14.8.2 пункта 8 [temp.deduct] следующим образом:

Если подмена приводит к недопустимого типа или выражение, тип вычет не может , Недопустимым типом или выражением является тот, который был бы плохо сформированным, если он написан с использованием замещенных аргументов. [Примечание: проверка доступа не выполняется как часть процесса замещения.-end note] Следовательно, при успешном завершении вывода ошибка при доступе может быть получена при вызове функции . Только недействительные типы ...

Так моя интерпретация, что это невозможно в C++ 03, но C++ 11 сделал это возможным.

1

Вот пример, который реализует is_comparable и обрабатывает потенциально закрытый оператор ==. g ++ - 4.7 дроссели на этом, но g ++ - 4.8 и clang ++ 3.4 корректно обрабатывают его в режиме 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