C++ 类内友元函数的返回类型推断

C++ 类内友元函数的返回类型推断,c++,auto,c++14,return-type-deduction,C++,Auto,C++14,Return Type Deduction,下面是一个关于for类内友元函数的小实验(在这两种情况下都使用clang3.4svn和g++4.8.1 withstd=c++1y),链接的工作文件中没有记录 #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

下面是一个关于for类内友元函数的小实验(在这两种情况下都使用clang3.4svn和g++4.8.1 with
std=c++1y
),链接的工作文件中没有记录

#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++
}
#包括
结构A
{
INTA_;
friend自动运算符==(常数与L、常数与R)
{ 
return L.a\u==R.a\u;//a\u的类型为int,因此应该返回bool
}
};
模板
结构B
{
int b_;
友元自动运算符==(B常量和L,B常量和R)
{ 
return L.b_==R.b_;//b_u的类型为int,因此应该返回bool
}
};
使用BI=B;
int main()
{

关于其他答案:我们在这里显式地处理它,以及它是如何在C++1y的最新草案中合并的

我使用的是来自的9514cc28,它已经对n3638进行了一些(较小的)修复/更改

n3638明确允许:

struct A {
  auto f(); // forward declaration
};
auto A::f() { return 42; }
而且,正如我们从[dcl.spec.auto]中可以推断的那样,在指定此功能的情况下,即使以下内容也是合法的:

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

A x;

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

int main() { x.f(); }
(稍后将对此进行详细介绍)

这与任何尾随的返回类型或依赖名称查找根本不同,因为
auto f();
是一个初步声明,类似于
struct a;
。在使用它之前(需要返回类型之前),需要稍后完成

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


OP的示例对n3638合法吗

这在我看来有点棘手。(我在本节中总是提到9514cc28。)

1.在哪里可以使用“自动”? [dcl.spec.auto]

6在本节未明确允许的上下文中使用
auto
decltype(auto)
的程序是格式错误的

2占位符类型可以与函数声明符一起出现在decl说明符seq、类型说明符seq、转换函数id或尾部返回类型中,在此类声明符有效的任何上下文中

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

因此,
auto func()
auto operator@(…)
通常是允许的(这源于函数声明的组成为
td
,其中
T
的形式为decl说明符seq,而
auto
是类型说明符)


2.是否允许写入“auto func();”,即不是定义的声明? [dcl.spec.auto]/1表示

auto
decltype(auto)
类型说明符指定一个占位符类型,该占位符类型将在以后被替换,可以通过从初始值设定项中进行推断,也可以通过带有尾部返回类型的显式规范进行替换

及/2

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

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


3.朋友功能如何? 到目前为止,这个例子

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_; }
应该是格式良好的。现在有趣的部分是
A
定义中友元函数的定义,即

struct A
{
    int a_;
    friend auto operator==(A const& L, A const& R)
    { return L.a_ == R.a_; } // allowed?
}
在我看来,这是允许的。为了支持这一点,我将引用名称查找。友元函数声明中定义的函数定义中的名称查找遵循[basic.lookup.unqual]中的成员函数名称查找/同一节的9./8规定了成员函数体内部使用的名称的非限定查找。声明使用名称的方法之一是“应为
X
类的成员或
X
(10.2)基类的成员”。这允许

struct X
{
    void foo() { m = 42; }
    int m;
};
请注意,
m
foo
中使用之前是如何声明的,但它是
X
的一个成员

由此,我得出结论,即使

struct X
{
    auto foo() { return m; }
    int m;
}
是允许的。这由clang++3.4 trunk 192325支持。 名称查找要求仅在
struct
完成后才解释此函数,还应考虑:

struct X
{
    auto foo() { return X(); }
    X() = delete;
};
类似地,类中定义的友元函数体只能在类完成后进行解释


4.模板呢? 具体来说,
friend auto some_函数(B const&L){return L.B_;}

首先,注入的类名
B
相当于
B
,请参见[temp.local]/1。它指的是当前实例化([temp.dep.type]/1)

id表达式
L.b
引用了当前实例化(/4)的一个成员。它也是当前实例化的一个依赖成员——这是在C++11之后添加的,请参阅,我不知道该怎么看:[temp.dep.expr]/5声明此id表达式不依赖于类型,就我所见[temp.dep.constepr]并不是说它依赖于价值

如果
L.b\uu
中的名称不是依赖的,则名称查找将遵循[temp.nondep]中的“常用名称查找”规则。否则,这将很有趣(依赖名称查找没有很好地指定),但考虑到这一点

template<class T>
struct A
{
    int foo() { return m; }
    int m;
};
模板
结构A
{
int foo(){return m;}
int m;
};
也被大多数编译器接受,我认为带有
auto
的版本也应该有效

在[temp.friend]中还有一个关于模板之友的部分,但在我看来,这里没有说明名称查找



另请参见。

我不认为问题具体在于模板中定义的友元函数。对于带有placeholde的函数模板,存在“返回类型推断”