类内友元函数的返回类型推导
Return type deduction for in-class friend functions
这里有一个关于类内友元函数的返回类型推导的小实验(在这两种情况下都使用Clang 3.4 SVN和g++4.8.1和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++
}
实例。
问题:C++14中是否支持类内友元函数的自动返回类型推导?
关于其他答案:我们在这里明确处理n3638,以及它是如何被纳入最近的C++1y草案中的。
我使用的是commitee的github存储库中的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构建无法编译,因为在解析行return L.b_ == R.b_;
时断言失败。到目前为止,我还没有检查过g++的最新版本。
OP的示例是否合法,适用于n3638?
这是一个有点棘手的IMO.(我在这一节中总是提到9514cc28。)
1.哪里允许使用"auto">
[dcl.spec.auto]
6 nbsp;在本节未明确允许的上下文中使用
auto
或decltype(auto)
的程序是格式错误的。2 占位符类型可以与函数声明符一起出现在decl说明符seq、类型说明符seq、转换函数id或尾部返回类型中,在任何声明符有效的上下文中。
/5也定义了一些上下文,但它们在这里无关紧要。
因此,auto func()
和auto operator@(..)
通常是允许的(这源于函数声明T D
的组成,其中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.uqual]/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中继192325支持的。名称查找需要仅在struct
完成后解释此函数,还需要考虑:
struct X
{
auto foo() { return X(); }
X() = delete;
};
类似地,类内部定义的友元函数体只能在类完成后进行解释。
4.模板呢
具体来说,friend auto some_function(B const& L) { return L.b_; }
呢?
首先,注入的类名B
等效于B<T>
,请参见[temp.local]/1。它指的是当前实例化([temp.dep.type]/1)。
id表达式L.b_
引用当前实例化的成员(/4)。它也是当前实例化的一个依赖于的成员——这是在C++11之后添加的,请参阅DR1471,我不知道该怎么想:[temp.dep.expr]/5声明这个id表达式是依赖于而不是依赖于类型的,而且据我所见,[temp.dep.comxpr]并没有说它是依赖于值的。
如果L.b_
中的名称不是依赖的,则名称查找将遵循"常规名称查找"规则。否则,这将很有趣(依赖名称查找没有很好地指定),但考虑到
template<class T>
struct A
{
int foo() { return m; }
int m;
};
也被大多数编译器所接受,我认为带有auto
的版本也应该是有效的。
在[temp.friend]中也有一个关于模板之友的部分,但在IMO中,它没有说明这里的名称查找。
也可以在isocpp论坛上看到这一高度相关的讨论。
- 如何获取std::result_of函数的返回类型
- 如何建立使用模板函数的lambda函数的尾部返回类型
- 在没有定义返回类型的函数中返回布尔值,并将结果保存在无错误的char编译中-为什么
- 特征::矩阵<双精度,1,3> 结构类型函数中的返回类型函数
- 函数作为模板参数,是否对返回类型强制约束
- C++中函数的向量返回类型引发错误
- 检查函数返回类型是否与STL容器类型值相同
- 警告:在函数返回类型 [-Wignore 限定符] 时忽略类型限定符
- 为什么 c++(g++) 不允许模板返回类型和函数名称之间有空格?
- 为什么返回类型的'const'限定符对标有 __forceinline/内联的函数没有影响?
- 在 c++ 中将函数返回类型指定为模板参数
- 使用 SWIG 更改生成的 CS 函数中的返回类型
- C++ 这里有一个返回 (24) 的布尔返回类型函数
- 使用SFINAE来检测void返回类型函数的存在
- 模板返回类型函数如何在C++中工作
- 如何在返回类型函数模板的专用化中使用派生类型?( "couldn't infer template argument" )
- Bon appetit :从 int 返回类型函数在 main() 中打印字符串
- 在引用或指针返回类型函数上输入
- 在后面的返回类型函数语法中,auto关键字背后是否有意图
- 我可以在c++中重写字符串返回类型函数吗?