C++ 类内友元函数的返回类型推断
下面是一个关于for类内友元函数的小实验(在这两种情况下都使用clang3.4svn和g++4.8.1 withC++ 类内友元函数的返回类型推断,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
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的函数模板,存在“返回类型推断”