C ++ - 转换函数模板演绎,为什么这个工作?

时间:2016-09-23 10:53:29

标签: c++ templates type-conversion implicit-conversion

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?

感谢。

2 个答案:

答案 0 :(得分:4)

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

由于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;,在返回类型中引用autodecltype。这不会发生在这里。

  
      
  1. 为什么转换功能模板可以访问A :: B?
  2.   

访问规则严格来说就是名称。 名称 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无效。