2016-09-23 68 views
8
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 ?C++ - 转换函数模板演绎,为什么这个工作?

感谢。

回答

4
  1. 为什么模板可以推导出类型是A :: B? (太聪明了!)

由于test()需要一个A::B,你需要一种方法来一个C转换为A::B。我们可以尝试用[over.match.conv]中的转换函数进行初始化:

考虑了S及其基类的转换函数。那些非显式转换 功能不隐藏在S和产量类型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所述。

基本上,我们推导出Ttemplate <class T> operator T()A::B。这是一个格式良好的转换序列,也是唯一可行的转换序列,所以就是这样。

您引用的行,关于“推导的返回类型”,指的是返回类型中的autodecltype。这不会发生在这里。

  1. 为什么转换函数模板可以访问A :: B?

访问规则严格限于名称。 名称B,只有名称,对于A是私有的。但我们没有访问名称,我们正在直接推断该类型。

B的构造函数是公共的,所以转换函数的主体也是格式良好的,所以关于代码的一切都是格式良好的。

+0

哦,我明白了。 '推导返回类型'在'7.1.7.4',但'转换函数模板不应该有推导返回类型'。这意味着'7.1.7.4'对'转换函数'没有任何东西。我不需要阅读'7.1.7.4'部分。 – Caesar

+0

我在哪里可以通过'type'而不是'name'获得有关访问控制的更多信息? – Caesar

+0

@Caesar没有类型的访问控制。 – Barry

0

要稍微过于简化的东西:

制作一个内部类或私人的功能仅意味着该类或函数的名称可以由类只使用,它是不可访问,否则。您不能在类之外编写任何使用私有类或函数的名称的代码。

在显示的代码中A::B不在类的任何地方使用。

这工作也为同样的确切原因:

class A { 

    class B {}; 

public: 

    B foo(); 
}; 


int main() 
{ 
    A a; 

    auto bar=a.foo(); 
    return 0; 
} 

auto作品。 A::B将无法​​使用。

相关问题