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