文中例程是本人自己理解和看网页的例子整理出来的,如有错误麻烦及时指正,水平有限,望与各位多多交流
这一节是对函数的声明和定义给一个总的概括的
原文地址:http://zh.cppreference.com/w/cpp/language/function
一下时注解和例程内容
1:函数声明
函数声明,通常是有返回类型和函数声明器组成,对于返回类型有decl-specifier-seq(见声明)组成,函数声明器可以是声明中声明器序列中的一个。
函数的声明器可以由:
noptr-declarator//所有合法的声明器
parameter-list //参数列表
attr //属性,针对函数类型,即针对之前的decl-specifier-seq的,如果要针对函数则需要在declarator中使用属性
cv //const/volatile
ref //限定,类成员
except //是否抛出异常(进行异常检测)
trailing //尾随返回
针对最后两点要知道,首先是确定这个函数不内所有操作不会出发异常时则可以使用noexcept使得不检查异常来提高一定的效率,通常,如果要通过参数类型运算来推断返回类型或者是返回值声明过于复杂的情况下的就使用尾随返回类型,对于使用尾随返回的函数decl-specifier-seq必为auto
对于函数返回值为auto推断的函数来说,更要注意的特殊规定是:不能用具体类型(或是其他的推导类型如decltype)来重新声明这个函数,即使我们的函数定义的推断是这个类型:
auto func();
auto func(){return 1;} //返回值auto推断为int
int func(); //error
decltype(12) func(); //error
对于一个用于推断返回类型的函数,要在类内表示友元,返回值必须指定为auto
template<typename T>
struct g
{friend auto func(T);
//friend T func(T); 不是友元
};
auto func(int i){return i;} //为g<int>的友元
另一个特殊情况就是当形参占位符为auto或是制约类型的情况下,这个函数将会被自动展开为一个模板来代替其中的占位符。
分清楚
template<typename T>auto g(T t){return t;}
template<typename T>T g(T t){return t;}
之间的区别,其中,更具之前的规则返回类型为auto的函数声明我们直到,这个函数声明时不能将auto替换为具体的一个类型,即使已有推断类型为这个具体类型的实例存在,所以当声明为
template int g(int);
template auto g(int);
对应的则是不同的匹配,当然这样很容易造成二义性:
g(12);
并且貌似没有办法避免这个二义性的造成。
2:参数表
参数列表就是之前总的声明的一个简化版,其中的声明器表改成了单独的一个声明器,并且要注意的是“…”前可以不加“,”所以可能会有这样子奇葩的声明:
template<typename ...T>
void f(T......){}
3:函数定义
函数定义实际上就是在声明的基础上扩充了几个规则:
function-body //函数体
ctor-initializer //初始化列表
compound-statement //语句块
function-try-block //函数try块
= delete; //函数默认删除
= default; //函数体默认定义
最后要注意的是:
函数的参数类型,还有返回类类型不能是不完整的类类型(void非类类型,这里不完整的类类型只的是一个前置定义的类并且在当前源文件内没有该类的定义或是当前的类),除了被删除的函数 (C++11 起)。完整性检查在函数体的语境中进行,这允许成员函数返回在其中定义它们定义的类(或其外围类),尽管在定义点它是不完整的(它在函数体内完整
)。
最后看一个例子:
struct TT
{
//virtual auto fe() { return 12; } //auto返回类型不能为虚函数
friend auto f1();
//friend int f1(); //和声明不兼容
//friend decltype(13) f1(); //同上,不能用其他形式的推导返回类型来声明
template<typename tt>
struct T1
{
//friend tt f1(); //该友元声明失败,没有直接定义相关返回tt类型的函数(定义了啧报错,因为仅返回类型相同,加上参数则正确(函数重载))
private:
int j = 0;
};
private:
int jj = 0;
};
auto f1()
{
TT::T1<int> ts;
//std::cout<<ts.j;
TT tss;
std::cout<<tss.jj;
return 13;
}
template<typename T> //#2
T fuc(T rs);
struct Ts
{
template<typename T> friend auto fuc(T); //友元声明成功
friend Ts fuc(Ts);
friend Ts fuc<Ts>(Ts);
template<typename ...Ty>
[[maybe_unused]] inline constexpr auto cmpfuc[[deprecated, maybe_unused]](Ty......)const && noexcept[[debug]]->decltype((12));
//该声明几乎涵盖了所有的函数声明元素.
private:
int jj = 0;
};
template<typename T> //#1
auto fuc(T re)
{
Ts sd;
std::cout << sd.jj;
return re;
}
Ts fuc(Ts re)
{
std::cout << re.jj;
return re;
}
template<typename T> //#2
T fuc(T rs)
{
Ts ds;
std::cout<<ds.jj; //OK,因为可以匹配第三个模板声明
return rs;
} //不要这么做,因为#1,#2会造成二义性,本例中不会,因为有一个非模板函数优先匹配。
template<typename ...Ty>
int main()
{
Ts J;
fuc(J);
int l = 0;
//fuc(l); //error
return 0;
}