处于默认参数位置的 Lambda 无法访问好友成员。这是编译器错误吗?
Lambda in default argument position can't access friend members. Is this a compiler bug?
我正在尝试编译一个用超现代神秘编码技术编写的程序。这些技术非常先进,GCC和Clang可以工作,但Visual Studio 2017会抛出错误。现在我想知道Visual Studio是否正确。
请考虑以下程序:
#include <functional>
#include <iostream>
class A
{
public:
A(int i) : foo(i) { }
private:
int foo;
friend class B;
};
class B
{
public:
void printFooFromA(const A& a, std::function<void (const A&)> printer = [](const A& a) {
std::cout << "a.foo is " << a.foo << std::endl;
}) {
printer(a);
}
};
int main()
{
A a(123);
B b;
b.printFooFromA(a);
return 0;
}
Visual Studio 抛出错误 C2248:"A::foo":无法访问在类"A"中声明的私有成员。
错误的根源在于 printFooFromA 的声明:"printer"参数以 lambda 的形式给出默认值。在 lambda 内部,它访问 A::foo。由于 foo 是私有的,因此只能在 A 或 A 的朋友内部访问。
这是否是一个错误取决于lambda是否应该被视为A的朋友。C++标准是否对此进行了规定?
编辑添加:StackOverflow 上存在关于 lambda 是否被视为类的朋友的问题,但这些问题都没有解决 lambda 处于默认参数位置的情况以及这是否符合标准C++。
根据C++17 [class.friend]/2
:将类声明为好友意味着可以在好友类的基本说明符和成员声明中访问授予友谊的类中的私有和受保护成员的名称。
声明类成员函数当然是成员声明,并且 lambda 肯定在声明中,所以我会将其解释为表示 lambda 具有友谊状态。
为了支持这一点,有[expr.prim.lambda.closure]/2:
闭包类型在包含相应 lambda 表达式的最小块作用域、类作用域或命名空间作用域中声明。[注意:这决定了与闭包类型关联的命名空间和类集。
所以lambda的闭包类型在B
的范围内声明,这意味着B
大致等价于:
class B
{
struct lam
{
void operator()(const A& a)
{
std::cout << "a.foo is " << a.foo << std::endl;
}
};
public:
void printFooFromA(const A& a, std::function<void (const A&)> printer = lam())
{
printer(a);
}
};
在 [class.friend]/2 中,它给出了一个具有相同布局的示例,表明friend class X;
意味着嵌套的X
类也是友元。
很明显,这是MSVC中的一个错误。
- 为什么派生类的好友不能使用受保护的成员?
- 消除好友和成员二进制运算符的歧义
- 好友功能 - 成员无法访问
- 无法从好友功能访问类的私有成员?"ostream"不是"std"的成员?
- MSVC 2017 - 错误 - 如何将模板类 X 的模板成员函数声明为嵌套类 X::Y 的好友
- 好友成员函数可以在单独的文件中使用吗?
- 处于默认参数位置的 Lambda 无法访问好友成员。这是编译器错误吗?
- 作为好友的非模板类的模板成员
- 好友 c++ 不适用于私有成员
- 好友与成员运算符重载的优先级
- 好友功能没有访问私人成员
- 嵌套类的类内好友是否可以访问外部类成员?
- 运算符<<不能使用其好友数组的 IT 成员
- 当我将一个类声明为其他类的成员时出现错误。 错误:声明好友时必须使用类键
- C++:将模板参数的模板类型成员加为好友的语法正确吗
- 好友功能无法访问私人数据成员
- 好友和静态成员函数具有什么样的成员访问权限
- 成员无法使用好友功能访问
- 通过好友访问受保护的成员
- 为什么我不能使这个成员函数成为另一个类的好友?