Может ли SFINAE обнаруживать нарушения приватного доступа?

Интересно, если я проверю для какого-то члена класса, а член является частным, что ответит sfinae? Будет ли это ошибкой, или она скажет, что все в порядке, или она будет ошибкой в ​​​​пути sfinae?


person Johannes Schaub - litb    schedule 24.01.2012    source источник
comment
... вы действительно проверяли это?   -  person user541686    schedule 24.01.2012
comment
Нет, я не тестировал. я не знаю полностью соответствующей реализации.   -  person Johannes Schaub - litb    schedule 24.01.2012
comment
@Mehrdad: но как интерпретировать результаты теста? Вы узнаете, как его интерпретирует компилятор, но как узнать, соответствует ли компилятор Стандарту?   -  person Matthieu M.    schedule 24.01.2012
comment
@MatthieuM.: О, я неправильно понял, что речь шла о соблюдении стандартов. Было бы полезно, если бы Йоханнес добавил это к вопросу.   -  person user541686    schedule 24.01.2012
comment
@meh я сделал на самом деле. я пометил его как c++ и не спрашивал ни о каком компиляторе. о чем, если бы не С++, был бы мой вопрос?   -  person Johannes Schaub - litb    schedule 24.01.2012
comment
@Mehrdad: большинство вопросов Йоханнеса касаются Стандарта и часто о пыльных углах, которые никто не осмеливался исследовать, опасаясь споткнуться о паутину и другие неприятные вещи, которые могут быть там найдены. Он наш Индиана Джонс ;)   -  person Matthieu M.    schedule 24.01.2012
comment
@MatthieuM.: Звучит немного странно, требовать, чтобы люди знали других людей здесь, чтобы правильно интерпретировать вопросы. Большинство вопросов SO, похоже, касаются практических проблем, которые необходимо решить, поэтому мне кажется совершенно обоснованным предположить, что это вопрос о практической проблеме, которую необходимо решить. Возможно, нам следует добавить некоторый тег (псевдоним) iso-c++, который даст понять, что людей больше интересует соответствие стандартам, чем работающее решение.   -  person PlasmaHH    schedule 24.01.2012
comment
Нет, меня интересует практичный и переносимый код.   -  person Johannes Schaub - litb    schedule 24.01.2012
comment
@PlasmaHH: Может быть. Лично я склонен интерпретировать вопрос в зависимости от репутации ОП. Я полагаю, что ОП с низкой репутацией, скорее всего, новички, а ОП с высокой репутацией должны знать, о чем говорят. Это несовершенно... но работает довольно хорошо :)   -  person Matthieu M.    schedule 24.01.2012
comment
Подойдет ли здесь тег language-lawyer?   -  person user541686    schedule 24.01.2012
comment
Это выглядит как совершенно подходящий нубский вопрос. я видел множество вопросов sfinae от чертовых новичков на stackoverflow.   -  person Johannes Schaub - litb    schedule 24.01.2012
comment
Юристские вопросы, похоже, представляют только теоретический интерес, но то, компилируется ли материал, имеет большое практическое значение.   -  person Johannes Schaub - litb    schedule 24.01.2012
comment
@JohannesSchaub-litb: практичность и портативность, к сожалению, в некоторых случаях являются взаимоисключающими (см. все обходные пути в boost).   -  person PlasmaHH    schedule 24.01.2012
comment
@MatthieuM.: Да, это работает хорошо, если только оно не терпит неудачу из-за того, что люди собирали свою репутацию на другом языке (или похожем);)   -  person PlasmaHH    schedule 24.01.2012
comment
@PlasmaHH: Сомневаюсь, я проверяю профиль ;) Однако также случается, что новички очень экспериментируют (Говард Хиннант появился на SO только в конце 2011 года) или что у опытных людей есть пробел...   -  person Matthieu M.    schedule 24.01.2012
comment
Ребята .. Этот вопрос относится к типу Can xxx, и я просто решил проголосовать за оба ответа Да. yyy и № zzz. Меня троллит логика и естественный язык.   -  person quetzalcoatl    schedule 26.04.2013


Ответы (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.

person Matthieu M.    schedule 24.01.2012

Нет. Я в дороге, и у меня нет стандарта, чтобы цитировать меня, но 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 сделал это возможным.

person PlasmaHH    schedule 24.01.2012

Я так не думаю.

11/4 «Управление доступом к участникам» (С++ 03):

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

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

person Michael Burr    schedule 24.01.2012
comment
Хм, я думал, что sfinae произойдет, если конструкция шаблона будет неправильно сформирована? - person Johannes Schaub - litb; 24.01.2012
comment
На самом деле кажется, что в [temp.deduct] есть специальное положение для замены. См. §14.8.2/8 в моем ответе. - person Matthieu M.; 24.01.2012

Вот пример, который реализует 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
person TimJ    schedule 24.07.2014