15

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?

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 3
    ... did you actually test it? – user541686 Jan 24 '12 at 08:48
  • 5
    No i didnt test it. i dont know of a completely conforming implementation. – Johannes Schaub - litb Jan 24 '12 at 08:50
  • 1
    @Mehrdad: but how interpret the output of the test ? You will know how the *compiler* interprets it, but how will you know whether the compiler is Standard compliant ? – Matthieu M. Jan 24 '12 at 08:51
  • @MatthieuM.: Oh I misunderstood that it was a question about standards compliance. It might be useful if Johannes adds that to the question. – user541686 Jan 24 '12 at 09:04
  • 2
    @meh i did actually. i tagged it as c++ and didnt ask about any compiler. what if not c++ would my question be about? – Johannes Schaub - litb Jan 24 '12 at 09:08
  • 1
    @Mehrdad: most of Johannes's questions are about the Standard, and often about dusty corners that no-one dared explore for fear of tripping on the cobwebs and other unsavory things that may be found there. He's our Indiana Jones ;) – Matthieu M. Jan 24 '12 at 09:11
  • 1
    @MatthieuM.: Sounds a bit weird to require people to know other people here to properly interpret questions. Most SO questions seem to be about practical problems to solve, so it seems perfectly valid for me to assume this is a question about a practical problem to solve. Maybe we should add some tag (alias) "iso-c++" that makes it clear people are more intrested in standards compliance than a working solution. – PlasmaHH Jan 24 '12 at 09:20
  • 2
    No i am interested in practical and portable code. – Johannes Schaub - litb Jan 24 '12 at 09:21
  • @PlasmaHH: Maybe. Personally I tend to interpret the question depending on the OP's reputation. I figure that OP with low-reputation are most likely beginners and OP with high reputation should know what they are talking about. It's imperfect... but works fairly well :) – Matthieu M. Jan 24 '12 at 09:23
  • 1
    Would the [tag:language-lawyer] tag be appropriate here? – user541686 Jan 24 '12 at 09:24
  • It appears like a perfectly appropriate noob question. i have seen loads of sfinae questions of bloody beginners on stackoverflow. – Johannes Schaub - litb Jan 24 '12 at 09:27
  • 1
    The lawyer kind of questions seem to be those that are only of theoretical interest but whether stuff compiles is highly of practical relevance. – Johannes Schaub - litb Jan 24 '12 at 09:28
  • @JohannesSchaub-litb: "practical and portable" are sadly mutually exclusive in certain cases (see all the workarounds in boost). – PlasmaHH Jan 24 '12 at 09:28
  • @MatthieuM.: Yeah, it works well, unless it fails miserably because the people have collected their reputation in a different language (or similar) ;) – PlasmaHH Jan 24 '12 at 09:29
  • @PlasmaHH: In doubt I check the profile ;) However it also happens that newbies are very experimented (Howard Hinnant only appeared on SO in late 2011) or that experienced people have a "blank"... – Matthieu M. Jan 24 '12 at 09:41
  • Guys.. This question is of "Can xxx" type and I just decided to upvote both a response "Yes. yyy" and "No. zzz". I feel trolled by logic and natural language. – quetzalcoatl Apr 26 '13 at 11:25

4 Answers4

11

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.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
5

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.

PlasmaHH
  • 15,673
  • 5
  • 44
  • 57
  • The need to begin this with "no" has probably aged away. Your last sentence should be your first. https://blog.jetbrains.com/clion/2020/06/dev-eco-cpp-2020/ – Spencer Sep 24 '21 at 14:13
2

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.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
1

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
TimJ
  • 839
  • 7
  • 6