考虑这段代码,其编写的唯一目的是练习:
class Param {
private:
struct Foo{
int bar;
};
public:
Foo foo;
};
int main()
{
Param p;
p.foo.bar = 5;
}
使用 cppInsight 生成此中间代码:
#include <cstdio>
class Param
{
private:
struct Foo
{
int bar;
// inline Foo() noexcept = default;
};
public:
Foo foo;
// inline Param() noexcept = default;
};
int main()
{
Param p = Param();
p.foo.bar = 5;
return 0;
}
一切看起来都很好,Param 可以实例化,bar 可以修改,但 Param::Foo 无法实例化。添加一个
int main()
{
Param p;
p.foo.bar = 5;
Param::Foo f = p.foo; // compile error
}
如预期的那样导致编译器错误。但是如果我尝试扣除自动
int main()
{
Param p;
p.foo.bar = 5;
auto f = p.foo; // it works!
}
它确实有效!
使用 cppInsight 检查新的生成代码,如下所示 this :
#include <cstdio>
class Param
{
private:
struct Foo
{
int bar;
// inline Foo() noexcept = default;
// inline constexpr Foo(const Foo &) noexcept = default;
};
public:
Foo foo;
// inline Param() noexcept = default;
};
int main()
{
Param p = Param();
p.foo.bar = 5;
Param::Foo f = Param::Foo(p.foo);
return 0;
}
使用 auto 的推导使编译器生成默认的复制构造函数并实际实例化。
有人可以解释为什么会发生这种行为吗?
最佳答案
将 Param::Foo
设为私有(private)意味着您无法通过此名称访问它。 C++ 标准在第 11.9 章(“成员访问控制”)中表示 [ C++20 draft N4860 PDF ]:
A member of a class can be
— private; that is, its name can be used only by members and friends of the class in which it is declared.
和
[Note: Access to members and base classes is controlled, not their visibility (6.4.10). Names of members are still visible, and implicit conversions to base classes are still considered, when those members and base classes are inaccessible. — end note]
(强调我的)
auto
不使用该名称。
这有时是故意的,例如用于容器的迭代器。这样您就可以仅将迭代器与 auto
一起使用。优点是容器的实现可以在稍后的时间点更改迭代器,而不会破坏您的代码(因为您需要切换到新名称)。
关于c++ - auto的推导使编译器生成默认构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75619237/