C++模板基础(六)

类模板与成员函数模板
● 使用 template 关键字引入模板: template class B {…};
– 类模板的声明与定义 翻译单元的一处定义原则

template<typename T>
class B; //类模板的声明

template<typename T>
class B //类模板的定义
{

};

template<typename T>
class B //类模板必须满足翻译单元级别的一处定义原则,Error: Redefinition of 'B'
{

};

– 成员函数只有在调用时才会被实例化

template<typename T>
class B //类模板的定义
{
public:
    void fun(T input)
    {
        std::cout << input << std::endl;
    }
};
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    B<int> x;
    x.fun(3);
    return a.exec();
}

在这里插入图片描述

template<typename T>
class B
{
public:
    void fun(T input)
    {
        std::cout << input << std::endl; //#1: Error: main.cpp:9:19: Invalid operands to binary expression ('std::ostream' (aka 'basic_ostream>') and 'Str')
    }
};

struct Str{};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    B<Str> y; //OK
    y.fun(Str{}); //该语句引发了#1处的报错,证明了成员函数只有在调用时才会被实例化
    return a.exec();
}

– 类内类模板名称的简写

template<typename T>
class B
{
public:
    auto fun()
    {
        return B<T>{}; //OK
        //如果该语句简写为return B{};,那么编译器自动视它为return B{};
        //如果模板参数为template class B;,那么编译器自动视return B{};为return B{};
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    B<int> x;
    x.fun(); //OK
    
    return a.exec();
}

– 类模板成员函数的定义(类内、类外)

template<typename T>
class B
{
public:
    void fun(); //类模板成员函数的声明
};

template<typename T>
void B<T>::fun() //OK, 规范类模板成员函数的类模板外定义
{

}

void B<T>::fun() //Oops, 错误的类模板成员函数的类模板外定义
{

}

● 成员函数模板
– 类的成员函数模板

class B
{
public:
    template <typename T>
    void fun() //类的成员函数模板的类内定义
    {
        std::cout << "template  void fun()\n";
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    B x;
    x.fun<int>();

    return a.exec();
}

在这里插入图片描述

class B
{
public:
    template <typename T>
    void fun(); //类的成员函数模板的类内声明
};

template<typename T>
void B::fun() //类的成员函数模板的类外定义
{
    std::cout << "template  void fun()\n";
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    B x;
    x.fun<int>();

    return a.exec();
}

– 类模板的成员函数模板

template<typename T> //#1
class B
{
public:
    template <typename T> //#2, 隐藏了#1处的T, Warning: Declaration of 'T' shadows template parameter
    void fun()
    {
        T  //是#1处的T还是#2处的T?
    }
    
private:
    T m_data; //#1处的T, OK
};
template<typename T>
class B
{
public:
    template <typename T2>
    void fun() //类模板的成员函数模板的类内定义
    {
        T2 tmp1; //OK
        T tmp2; //OK
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    B<int> x;
    x.fun<float>(); //OK

    return a.exec();
}
template<typename T>
class B
{
public:
    template <typename T2>
    void fun(); //类模板的成员函数模板的类内声明
};

template<typename T>
template <typename T2>
void B<T>::fun() //类模板的成员函数模板的类外定义
{
    T2 tmp1; //OK
    T tmp2; //OK
}

用google搜索引擎搜索gcc github vector可以搜到vector的实现

● 友元函数(模板)

template <typename T2>
void fun(); //友元函数模板的声明

template<typename T>
class B
{
    template <typename T2>
    friend void fun(); //声明该函数模板为类的模板的友元

    int x;
};

template <typename T2>
void fun() //定义
{
    B<int> tmp1;
    tmp1.x; //OK

    B<char> tmp2;
    tmp2.x; //OK
}

– 可以声明一个函数模板为某个类(模板)的友元

template<typename T>
class B
{
    friend void fun(B input) //被编译器解析为B
    {
        std::cout << input.x << std::endl;
    }

    int x = 3;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    B<int> val;
    fun(val);

    B<float> val2;
    fun(val2);

    return a.exec();
}
template<typename T>
class B
{
    friend auto operator + (B input1, B input2) //由#1,被视为B,是B的友元函数,但不是B的友元函数
    {
        B res;
        res.x = input1.x + input2.x;

        B<float> tmp; //
        tmp.x; //Error: 'x' is a private member of 'B'

        return res;
    }

    int x = 3;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    B<int> val1;
    B<int> val2;
    B<int> res = val1 + val2; //#1,此处用int实例化

    return a.exec();
}

– C++11 支持声明模板参数为友元

template<typename T>
class B
{
    friend T; //OK Since C++11
};

● 类模板的实例化 (class_template)
– 与函数实例化很像
– 可以实例化整个类,或者类中的某个成员函数
● 类模板的(完全)特化 / 部分特化(偏特化)

#include
template <typename T>
struct B
{
	void fun()
	{
		std::cout << "template