Can SFINAE detect private access violations?

余生颓废 提交于 2019-11-26 11:26:45

问题


I wonder whether if i test for some member of a class and the member is private what will sfinae respond? Will it error out hard or will it say ok or will it error out in the sfinae way?


回答1:


Yes.

EDIT: C++11 Standard quote from §14.8.2 [temp.deduct]

8/ If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. [ Note: Access checking is done as part of the substitution process. —end note ]

This suggests to me that private can trigger an SFINAE error. Reading on:

Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed.—end note ]

The "immediate context" is not so clear to me... but it does not contradict my point :)

end of EDIT

So it seems to me that it will error out in an SFINAE way, this is further confirmed by this excerpt from 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
  };

There are special cases with regard to Access Control in the case of SFINAE.




回答2:


No. I am on the road and don't have a standard to quote with me, but sfinae takes places in the phase of compilation where the compiler checks if the name exists at all, and in a later phase access control takes place.

This is similar to overload resolution, where all names are considered, and a match that is private is better, but won't compile, although there is another match that would be "ok" but not private.

Addition:

Core issue 1170 says:

1170 Access checking during template argument deduction
Section: 14.8.2 [temp.deduct]
Status: FDIS Submitter: Adamczyk Date: 2010-08-03

[Voted into the WP at the March, 2011 meeting.]

According to 14.8.2 [temp.deduct] paragraph 8,

Access checking is not done as part of the substitution process. Consequently, when deduction succeeds, an access error could still result when the function is instantiated.

This mimics the way access checking is done in overload resolution. However, experience has shown that this exemption of access errors from deduction failure significantly complicates the Standard library, so this rule should be changed.

Proposed resolution (January, 2011):

Change 14.8.2 [temp.deduct] paragraph 8 as follows:

If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. [Note: Access checking is not done as part of the substitution process. —end note] Consequently, when deduction succeeds, an access error could still result when the function is instantiated. Only invalid types...

So my interpretation is that this is impossible in C++03, but C++11 made it possible.




回答3:


I don't think so.

11/4 "Member access control" (C++03):

The interpretation of a given construct is established without regard to access control. If the interpretation established makes use of inaccessible member names or base classes, the construct is ill-formed.

So overload resolution occurs first, then access control is applied.




回答4:


Here is an example that implements is_comparable and handles a potentially private operator==. g++-4.7 chokes on this, but g++-4.8 and clang++ 3.4 handle it correctly in C++11 mode.

#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


来源:https://stackoverflow.com/questions/8984013/can-sfinae-detect-private-access-violations

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!