SFINAE 能否检测私人访问违规行为?

发布于 2024-12-28 18:15:40 字数 80 浏览 2 评论 0原文

我想知道如果我测试某个类的某个成员并且该成员是私有的,sfinae 会做出什么反应?它会严重出错还是会说“ok”或者会以 sfinae 方式出错?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

你在看孤独的风景 2025-01-04 18:15:40

是的。

编辑:来自§14.8.2 [temp.deduct]的C++11标准引用

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 的情况下,存在关于访问控制的特殊情况。

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.

音盲 2025-01-04 18:15:40

不。我正在路上,没有可以引用的标准,但 sfinae 发生在编译阶段,编译器检查名称是否存在,并在稍后的阶段进行访问控制。

这类似于重载解析,其中考虑所有名称,并且私有的匹配更好,但不会编译,尽管还有另一个匹配“ok”但不是私有的。

补充:

核心问题 1170 说:

1170 模板参数推导期间的访问检查
部分:14.8.2 [温度扣除]
状态:FDIS 提交者:Adamczyk 日期:2010-08-03

[在 2011 年 3 月的会议上投票加入 WP。]

根据 14.8.2 [temp.deduct] 第 8 段,

<块引用>

访问检查不会作为替换过程的一部分进行。因此,当推导成功时,仍然可能出现访问错误
函数实例化时的结果。

这模仿了在重载解析中完成访问检查的方式。
然而,经验表明,这种访问错误的豁免
推导失败使标准库显着复杂化,
所以这个规则应该改变。

拟议决议(2011 年 1 月):

将 14.8.2 [temp.deduct] 第 8 段更改如下:

<块引用>

如果替换导致无效类型或表达式,类型推导将失败。无效的类型或表达式是
如果使用替换的参数编写,则格式错误。 [注:访问
检查不是作为替换过程的一部分进行的。 ——尾注]
因此,当推导成功时,仍然可能出现访问错误
函数实例化时的结果。仅无效类型...

所以我的解释是这在 C++03 中是不可能的,但 C++11 使它成为可能。

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.

爱你是孤单的心事 2025-01-04 18:15:40

我不这么认为。

11/4“成员访问控制”(C++03):

对给定结构的解释是在不考虑任何因素的情况下建立的
来进行访问控制。如果所建立的解释利用
无法访问的成员名称或基类,其构造是
格式错误。

因此,首先发生重载解析,然后应用访问控制。

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.

红玫瑰 2025-01-04 18:15:40

下面是一个实现 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

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文