c++模板的引用类型参数折叠问题解释

Posted 大黑耗

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++模板的引用类型参数折叠问题解释相关的知识,希望对你有一定的参考价值。

template<typename T> void f1(T&);   

实参可以是左值、const类型的左值,不能是右值。

f1(i);   // 正确,i是int型,T是int

f1(c);  // 正确,i是const int 型,T是const int

f1(5);  // 错误

 

template<typename T> void f1(const T&);    

实参可以是左值、const类型的左值、右值。

f1(i);  // 正确,i是int型,T是int

f1(c);  // 正确,c是const int 型,T是int

f1(5);  // 正确,5是int&&,T是int

 

template<typename T> void f1(T&&);   

我们可能认为给这种情况传递一个左值给f1是不合法的,但实际上这是合法的,这种情况的实参可以是左值(或左值引用)(无论有无const)、右值(或右值引用)。

1. 当实参是右值(或右值引用)的时候,T被推断为X

f1(5);  // 正确,5是int&&型,T是 int

2. 例外规则①:当模板参数是右值(T&&)而实参是左值(或左值引用),也合法,此时T被推断为X&

f1(i);   // 正确,i是int型,按照上面的规则,T是 int&

 

第1种情况我们很容易理解,因为类型完全匹配。

对于第2种情况,根据例外规则①,把T代入,这个f1模板被实例化为 f1(int& &&) ,它的参数是引用的引用,那为啥我们实际传入的是 int& 咧?对于这种情况,实际上是c++有第2条例外规则:引用折叠。

例外规则②:引用折叠(当出现引用的引用类型变量时就会发生引用折叠)

X& &、X& &&、X&& & 这三种等价折叠为 X&

X&& && 等价折叠为 X&&

所以对于  f1(int& &&) ,它等价于 f1(int &),因此我们传入 int& 的实参是可以的。

c++11新特性之引用折叠

引用折叠的前提是出现了引用的引用,有点绕。我们不能直接定义引用的引用,但是可以间接定义。

通过类型别名或者通过模板参数间接定义,多重引用最终折叠成左值引用或者右值引用,多余的忽略

typedef int&& new_type;

new_type& ok;

这个时候就形成了类型折叠 类似于int&&& ok;最后折叠成int& ok;

template<typename T> void test(T&& t);

如果参数传入一个引用类型例如int m=0;int& n=m;template<int&> test(n);这个时候也形成了引用折叠,最终参数保留了引用特性

template<typename T> void test6(T&& t)//传入引用就会形成折叠
{
    printf("%d\\n", t++);
}
int main(int narg, char**)
{
    typedef int&& new_int;
    int n = 0;
    new_int& a=n;//引用折叠int&&& 最终成为int&
    a = 10;
    printf("%d\\n", n);

    test6(a);
    printf("%d\\n", n);
    system("pause");
    return 0;
}

 

以上是关于c++模板的引用类型参数折叠问题解释的主要内容,如果未能解决你的问题,请参考以下文章

Effective Modern C++ 条款28 理解引用折叠

切换基于模板类型 C++ 的引用参数传递

局部变量的引用折叠

c++11新特性之引用折叠

C++ Primer 5th笔记(chap 16 模板和泛型编程)模板实参推断和引用

C++进阶第二十五篇——C++11(列表初始化+变量类型推导+右值引用和移动语义+新的类功能+可变模板参数)