class A
{
struct B{};
public:
static void test(A::B){}
};
struct C
{
template<class T>
operator T()
{
return T();
}
};
int main()
{
A::test(C());
}
此代码适用于clang 3.7,gcc 5.1和vc ++ 14.2
2个问题,
1.为什么模板推导出的类型是A :: B? (太聪明了!)
据我所知,模板通过return语句而不是参数来推断类型
但是我发现了一些对N4606 12.3.2 6 A conversion function template shall not have a deduced return type (7.1.7.4).
感兴趣的东西(但是,我无法找到关于此的更多信息,因为7.1.7.4太难理解了。)
2.为什么转换函数模板可以访问A :: B?
感谢。
答案 0 :(得分:4)
- 为什么模板推导出的类型是A :: B? (太聪明了!)
醇>
由于test()
需要A::B
,您需要一种方法将C
转换为A::B
。我们可以尝试通过转换函数进行初始化,我们在[over.match.conv]中有了这个函数:
考虑
S
及其基类的转换函数。那些非显式转换 未隐藏在S
和yield类型T
中的函数或可通过类型转换为T
类型的类型 标准转换序列(13.3.3.1.1)是候选函数。
我们根据[temp.conv]进行模板演绎:
模板参数推导是通过比较转换函数模板的返回类型(调用)来完成的 P)具有转换结果所需的类型(称之为A;见8.6,13.3.1.5和13.3.1.6 确定该类型)如14.8.2.5所述。
基本上,我们会将T
中的template <class T> operator T()
推断为A::B
。这是一个结构良好的转换序列,也是唯一可行的转换序列,因此会发生什么。
您引用的行,关于&#34;推断的返回类型&#34;,在返回类型中引用auto
或decltype
。这不会发生在这里。
- 为什么转换功能模板可以访问A :: B?
醇>
访问规则严格来说就是名称。 名称 B
,只有名称,对A
是私有的。但我们没有访问名称,我们直接推断出该类型。
B
的构造函数是公共的,因此转换函数的主体也是格式良好的,因此代码的所有内容都是格式良好的。
答案 1 :(得分:0)
略微过分简化:
使内部类或函数仅为私有意味着类或函数的名称只能由类使用,否则无法访问。您不能在类之外编写任何使用私有类或函数名称的代码。
在显示的代码中,A::B
不会在课堂外的任何地方使用。
这也有效,原因完全相同:
class A {
class B {};
public:
B foo();
};
int main()
{
A a;
auto bar=a.foo();
return 0;
}
auto
有效。 A::B
无效。