我做了这个简单的课程,但仍在玩我的想法:
class A {
private:
class B {};
public:
B getB() {
return B();
};
};
从C ++ 03开始,这个类编译得很好,但是没有漂亮的方式将getB()
的结果分配给左值,意思是:< / p>
A::B b = A().getB();
不编译。
我通过这种方式使用中间模板得到它:
template <typename T>
struct HideType {
typedef T type;
};
HideType<A::B>::type b = A().getB();
但这看起来很糟糕,因为这个简单的任务是获得一个A :: B左值变量。
从C ++ 11开始,这不再是真的,或者至少它不适用于gcc。此代码仍无效:
A::B b = A().getB();
但 有效:
auto b = A().getB();
标准方面是否存在漏洞?
答案 0 :(得分:9)
从标准,第11条(会员访问控制):
班级成员可以是 - 私人的;也就是说,它的名称只能由声明它的类的成员和朋友使用。
- 受保护;也就是说,它的名称只能由其所在类的成员和朋友使用 通过该类派生的类及其朋友宣布(见11.4) - 上市;也就是说,它的名称可以在没有访问限制的任何地方使用。
因此,访问控制适用于名称。
在
auto b = A().getB();
根据标准
,您不使用私人名称,因此它是合法的答案 1 :(得分:1)
A::B b = A().getB()
不起作用的事实是因为B
是A
的私有类成员。如果你把它公开,那么你的代码将被编译。它适用于auto
,因为auto
只检查分配给它的对象的类型,而无需调用对象的构造函数(就像declval
)。因此,它会为b
分配类getB
中的返回类型A
。您也可以通过以下方式更改代码:
decltype( declval<A>().getB() ) b = A().getB();
(如果declval
对您来说是新的,那么我必须告诉您它将返回函数返回类型的右值(此处为getB
,其返回类型为B
)一个类(这里A
)没有调用类的构造函数!(但是这应该仅用于decltype
和sizeof
之类的函数。)因此它可以防止创建类的开销对象然后使用它的功能。)
现在根据我的说法,我认为这不是标准中的漏洞而是我觉得漏洞已被删除!从您自己的代码中可以看出,请参阅函数getB
。实例化B
的对象有多困难,因为它是私有定义的!在这种情况下,使用B
变得困难。这背后的想法是类B
中的类型名称(即A
)是不可访问的,但类型仍然可用,这就是为什么你可以获得B
的对象。如果您了解此模板代码,则可以了解auto
的使用: -
#include <iostream>
#include <type_traits> // for std::is_same
using namespace std;
class A
{
class B
{};
public:
B getB()
{
return B();
}
};
template<typename T>
void check (T b)
{
cout<<boolalpha;
is_same<decltype( declval<A>().getB() ), T> x; // checks if T & B are of same type
cout<<x.value<<'\n';
}
int main()
{
A obj;
check (obj.getB());
return 0;
}
输出: -
true
由于template
可以识别B
,因此auto
也会识别B
。
答案 2 :(得分:0)
看来,标准草案中存在这样的缺陷,但已由WP 1170更正。
可能存在编译器错误。声明auto b = A().getB();
涉及auto
类型说明符的模板参数推导,因此根据C ++ 11标准,它应该是格式错误的,因为类型推导失败