Может ли SFINAE обнаруживать нарушения частного доступа?
Интересно, если я тестирую какого-то члена класса, а член является частным, что ответит sfinae? Будет ли это ошибка, или она скажет "ОК", или это будет ошибка в режиме sfinae?
Ответы
Ответ 1
Да.
EDIT: С++ 11 Стандартная цитата из §14.8.2 [temp.deduct]
8/ Если подстановка приводит к недопустимому типу или выражению, тип дедукции терпит неудачу. Недопустимый тип или выражение - это те, которые были бы плохо сформированы, если они были написаны с использованием замещенных аргументов. [Примечание. Проверка доступа выполняется как часть процесса замещения. -end note]
Это говорит мне, что private
может вызвать ошибку SFINAE. Чтение:
Только недопустимые типы и выражения в непосредственном контексте типа функции и ее типа параметров шаблона могут привести к ошибке дедукции. [Примечание: оценка замещенных типов и выражений могут приводить к побочным эффектам, таким как создание специализированных специализированных шаблонов классов и/или функций, генерация неявно определенных функций и т.д. Такие побочные эффекты не находятся в "непосредственном контексте" и могут приводить к в программе плохо сформированы.-end note]
"Непосредственный контекст" мне не очень понятен... но это не противоречит моей точке:)
конец 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
Нет. Я нахожусь в дороге и не имею стандарта, чтобы процитировать со мной, но sfinae занимает места в фазе компиляции, где компилятор проверяет, существует ли это имя вообще, и в более позднем фазовом управлении доступом.
Это похоже на разрешение перегрузки, где рассматриваются все имена, а совпадение является частным лучше, но не будет компилироваться, хотя есть еще одно совпадение, которое было бы "нормально", но не частным.
Дополнение:
Основная проблема 1170 говорит:
1170 Проверка доступа при выводе аргумента шаблона
Раздел: 14.8.2 [temp.deduct]
Статус: FDIS Отправитель: Adamczyk Дата: 2010-08-03
[Проголосовал в WP на встрече в марте 2011 года.]
Согласно пункту 14.8.2 [temp.deduct],
Проверка доступа не выполняется как часть процесса замещения. Следовательно, когда вычет преуспевает, ошибка доступа все еще может быть результат при создании экземпляра функции.
Это напоминает, как проверка доступа выполняется при разрешении перегрузки. Однако опыт показал, что это исключение ошибок доступа от дедуктивного отказа значительно усложняет библиотеку Standard, поэтому это правило должно быть изменено.
Предлагаемая резолюция (январь 2011 года):
Измените 14.8.2 [temp.deduct] пункт 8 следующим образом:
Если подстановка приводит к недопустимому типу или выражению, тип дедукции не выполняется. Недопустимым типом или выражением является тот, который был бы плохо сформированный, если он написан с использованием замещенных аргументов. [Примечание: доступ проверка не выполняется как часть процесса замещения. -end note] Следовательно, когда вычет преуспевает, ошибка доступа все еще может быть результат при создании экземпляра функции. Только недопустимые типы...
Итак, моя интерпретация заключается в том, что это невозможно в С++ 03, но С++ 11 сделал это возможным.
Ответ 3
Я так не думаю.
11/4 "Контроль доступа элемента" (С++ 03):
Интерпретация данной конструкции устанавливается без учета для контроля доступа. Если установленная интерпретация использует недоступные имена членов или базовые классы, конструкция плохо сформирован.
Сначала возникает разрешение перегрузки, затем применяется управление доступом.
Ответ 4
Вот пример, который реализует is_comparable и обрабатывает потенциально закрытый оператор ==. g++ - 4.7 дросселей на этом, но g++ - 4.8 и clang++ 3.4 корректно обрабатывают его в режиме С++ 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