针对课堂朋友功能的返回类型扣除

Tem*_*Rex 30 c++ auto return-type-deduction c++14

这是一个关于类内朋友函数的返回类型推导的小实验(std=c++1y在两种情况下都使用Clang 3.4 SVN和g ++ 4.8.1 ),链接工作文件中没有记录

#include <iostream>

struct A
{
    int a_;
    friend auto operator==(A const& L, A const& R) 
    { 
        return L.a_ == R.a_; // a_ is of type int, so should return bool
    }
};

template<class T>
struct B
{
    int b_;
    friend auto operator==(B const& L, B const& R) 
    { 
        return L.b_ == R.b_; // b_ is of type int, so should return bool
    }
};

using BI = B<int>;

int main()
{
    std::cout << (A{1} == A{2}) << "\n";    // OK for Clang, ERROR for g++
    std::cout << (BI{1} == BI{2}) << "\n";  // ERROR for both Clang and g++
}
Run Code Online (Sandbox Code Playgroud)

实例.

问题:C++ 14支持的类内朋友函数的自动返回类型推导?

dyp*_*dyp 11

关于其他答案:我们在这里明确地处理了n3638,以及它如何被包含在最近的C++ 1y草案中.

我正在使用来自commitee的github存储库的 9514cc28 ,它已经对n3638进行了一些(次要的)修复/更改.

n3638明确允许:

struct A {
  auto f(); // forward declaration
};
auto A::f() { return 42; }
Run Code Online (Sandbox Code Playgroud)

而且,正如我们可以从[dcl.spec.auto]推断出指定此功能的地方,即使以下内容也是合法的:

struct A {
  auto f(); // forward declaration
};

A x;

auto A::f() { return 42; }

int main() { x.f(); }
Run Code Online (Sandbox Code Playgroud)

(但稍后会详细介绍)

这与任何尾随返回类型或从属名称查找根本不同,auto f();初步声明类似于struct A;.它需要在使用之前(在需要返回类型之前)完成.

此外,OP中的问题与内部编译器错误有关.最近的clang ++ 3.4 trunk 192325 Debug + Asserts构建无法编译,因为断言在解析行时失败return L.b_ == R.b_;.到目前为止,我还没有使用最新版本的g ++进行检查.


OP的例子是否合法到n3638?

这是一个有点棘手的IMO.(我在本节中总是指9514cc28.)

1.哪里可以使用`auto`?

[dcl.spec.auto]

6 在本节中未明确允许使用autodecltype(auto)在其中使用的程序格式不正确.

2 在这样的声明有效的任何上下文中,占位符类型可以在decl-specifier-seq,type-specifier-seq,conversion-function-idtrailing-return-type中与函数声明符一起出现.

/ 5也定义了一些上下文,但它们在这里无关紧要.

因此,auto func()auto operator@(..)通常都可以(从一个函数声明的组合物此为如下T D,其中,T具有以下形式DECL说明符-SEQ,并且auto是一个类型说明符).


2.是否允许编写`auto func();`,即一个不是定义的声明?

[dcl.spec.auto]/1说

autodecltype(auto) 类型说明符指定将以后,无论是通过从一个初始化扣除或通过用明确的规范被替换的占位符类型尾返回型.

和/ 2

如果函数的声明返回类型包含占位符类型,则函数的返回类型将从return函数体中的语句推导出来(如果有).

虽然它没有明确允许类似于auto f();函数的声明(即没有定义的声明),但从n3638和[dcl.spec.auto]/11可以清楚地看出它是允许的,而不是明确禁止的.


朋友的功能怎么样?

到目前为止,这个例子

struct A
{
    int a_;
    friend auto operator==(A const& L, A const& R);
}

auto operator==(A const& L, A const& R)
{ return L.a_ == R.a_; }
Run Code Online (Sandbox Code Playgroud)

应该是格式良好的.现在有趣的部分是定义中定义的友元函数A,即

struct A
{
    int a_;
    friend auto operator==(A const& L, A const& R)
    { return L.a_ == R.a_; } // allowed?
}
Run Code Online (Sandbox Code Playgroud)

在我看来,这是允许的.为了支持这一点,我将引用名称查找.在友元函数声明中定义的函数定义中的名称查找遵循[basic.lookup.unqual]/9的成员函数的名称查找.同一部分的/ 8指定对成员函数体内使用的名称进行非限定查找.可以声明使用名称的方式之一是它"应该是类X的成员或者是X(10.2)的基类的成员".这使得广为人知

struct X
{
    void foo() { m = 42; }
    int m;
};
Run Code Online (Sandbox Code Playgroud)

注意m在使用foo它之前是如何声明的,但是它是成员X.

从这一点,我得出结论,甚至

struct X
{
    auto foo() { return m; }
    int m;
}
Run Code Online (Sandbox Code Playgroud)

被允许.这是由clang ++ 3.4 trunk 192325支持的.名称查找只需要struct在完成后解释此函数,还要考虑:

struct X
{
    auto foo() { return X(); }
    X() = delete;
};
Run Code Online (Sandbox Code Playgroud)

类似地,只有在类完成后才能解释类中定义的友元函数体.


4.模板怎么样?

具体来说,怎么样friend auto some_function(B const& L) { return L.b_; }

首先,inject -class-name B相当于B<T>,参见[temp.local]/1.它指的是当前的实例化([temp.dep.type]/1).

所述ID-表达 L.b_指的是当前实例的构件(/ 4).它也是当前实例化依赖成员 - 这是在C++ 11之后添加的,参见DR1471,我不知道该怎么想:[temp.dep.expr]/5声明这个id -expression没有类型相关,而据我见[temp.dep.constexpr]不说,它的价值依赖.

如果名称in L.b_不依赖,则名称查找将遵循每个[temp.nondep]的"通常名称查找"规则.否则,这将是有趣的(依赖名称查找不是很好指定),但考虑到这一点

template<class T>
struct A
{
    int foo() { return m; }
    int m;
};
Run Code Online (Sandbox Code Playgroud)

也被大多数编译器所接受,我认为版本也auto应该是有效的.

在[temp.friend]中还有一个关于模板朋友的部分,但IMO并没有说明这里的名字查找.


另请参阅isocpp-forum中此高度相关的讨论.