当前位置: 首页 > article >正文

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<char, char_traits<char>>') 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<int>{};
        //如果模板参数为template<typename T1, typename T2> class B;,那么编译器自动视return B{};为return B<T1, T2>{};
    }
};

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 <typename T> 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 <typename T> 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<T>
    {
        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<int>,是B<int>的友元函数,但不是B<float>的友元函数
    {
        B res;
        res.x = input1.x + input2.x;

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

        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<iostream>
template <typename T>
struct B
{
	void fun()
	{
		std::cout << "template <template T> void B::fun()" << std::endl;
	}
};

template<>
struct B<int>
{
	void fun()
	{
		std::cout << "template<> void B<int> fun()" << std::endl;
	}
};

int main()
{
	B<int> x;
	x.fun();
	return 0;
}

在这里插入图片描述

#include<iostream>
template <typename T, typename T2>
struct B
{
	void fun()
	{
		std::cout << "template <template T, typename T2> void B::fun()" << std::endl;
	}
};

template<typename T>
struct B<int, T>
{
	void fun2()
	{
		std::cout << "template<typename T> void B<int, T> fun2()" << std::endl;
	}
};

int main()
{
	B<int, double> x;
	x.fun2();
	return 0;
}

在这里插入图片描述

template <typename T, typename T2>
struct B
{
	void fun()
	{
		std::cout << "template <template T> void B::fun()" << std::endl;
	}
};

template<typename T> //更换模板参数名称并不会对模板的代码逻辑产生影响
struct B<int, T>
{
	void fun2()
	{
		std::cout << "template<> void B<int> fun2()" << std::endl;
	}
};
#include<iostream>
template <typename T>
struct B
{
	void fun()
	{
		std::cout << "template <template T> void B::fun()" << std::endl;
	}
};

template<typename T>
struct B<T*> //部分特化
{
	void fun2()
	{
		std::cout << "template<typename T> void B<T*> fun2()" << std::endl;
	}
};

int main()
{
	B<int*> x;
	x.fun2();
	return 0;
}

在这里插入图片描述

– 特化版本与基础版本可以拥有完全不同的实现

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

template<>
struct B<int>
{
	void fun2()
	{
		std::cout << "template<> void B<int> fun2()" << std::endl;
	}
};

int main()
{
	B<int> x;
	//x.fun(); //Error: class B<int>没有成员fun()
	x.fun2();
	return 0;
}

在这里插入图片描述

● 类模板的实参推导(从 C++17 开始)
– 基于构造函数的实参推导

#include<iostream>
template <typename T>
struct B
{
	B(T input)
	{}

	void fun()
	{
		std::cout << "template <template T> void B::fun()" << std::endl;
	}
};
int main()
{
	B x(3);
	return 0;
}
//CPPINSIGHTS里面的输出
#include<iostream>
template<typename T>
struct B
{
  inline B(T input)
  {
  }
  
  inline void fun()
  {
    std::operator<<(std::cout, "template <template T> void B::fun()").operator<<(std::endl);
  }
  
};

/* First instantiated from: insights.cpp:15 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct B<int>
{
  inline B(int input)
  {
  }
  
  inline void fun();
  
};

#endif



/* First instantiated from: insights.cpp:15 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
B(int input) -> B<int>;
#endif
int main()
{
  B<int> x = B<int>(3);
  return 0;
}

#include<iostream>
template <typename T>
struct B
{
	B(T* input)
	{}

	void fun()
	{
		std::cout << "template <template T> void B::fun()" << std::endl;
	}
};
int main()
{
  int i = 3;
  B x(&i);
	return 0;
}
//CPPINSIGHTS里面的输出
#include<iostream>
template<typename T>
struct B
{
  inline B(T * input)
  {
  }
  
  inline void fun()
  {
    std::operator<<(std::cout, "template <template T> void B::fun()").operator<<(std::endl);
  }
  
};

/* First instantiated from: insights.cpp:16 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
struct B<int>
{
  inline B(int * input)
  {
  }
  
  inline void fun();
  
};

#endif



/* First instantiated from: insights.cpp:16 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
B(int * input) -> B<int>;
#endif
int main()
{
  int i = 3;
  B<int> x = B<int>(&i);
  return 0;
}

– 用户自定义的推导指引
– 注意:引入实参推导并不意味着降低了类型限制!

#include<iostream>
#include<utility>
int main()
{
	std::pair<int, double> x{ 3, 3.14 };
	x.first = "123456"; //Error: 不能将 "const char *" 类型的值分配到 "int" 类型的实体
	return 0;
}

– C++ 17 之前的解决方案:引入辅助模板函数

#include<iostream>
#include<utility>
int main()
{
	std::pair x{ 3, 3.14 }; //Error: 缺少类模板 "std::pair" 的参数列表
	return 0;
}
#include<iostream>
#include<utility>
template<typename T1, typename T2>
std::pair<T1, T2> make_pair(T1 val1, T2 val2)
{
	return std::pair<T1, T2>(val1, val2);
}
int main()
{
	auto x = make_pair(3, 3.14); //OK
	return 0;
}

参考
深蓝学院:C++基础与深度解析
cppinsights
cppreference


http://www.kler.cn/a/9374.html

相关文章:

  • 【MySQL】数据库知识突破:数据类型全解析与详解
  • luckfox-pico-max学习记录
  • 障碍检测与避障控制 ROS2机器人
  • 使用Matlab神经网络工具箱
  • 【AI写作宝-注册安全分析报告-无验证方式导致安全隐患】
  • 爬虫如何解决短效代理被封的问题?
  • 故障定级和定责
  • 处理机调度与死锁习题
  • 蓝桥杯第十四届省赛完整题解 C/C++ B组
  • Window常用命令
  • Dubbo架构整体设计
  • 小规模容器编排使用Docker Swarm不香么,用个锤子的kubernetes
  • Leetcode.2399 检查相同字母间的距离
  • webpack介绍
  • 三十四、java中的引用
  • react简单实现防抖和节流教程方法
  • 用于平抑可再生能源功率波动的储能电站建模及评价(Matlab代码实现)
  • 【前端做项目常用】相关插件的官网 总结
  • 【web自动化测试】
  • LinuxGUI自动化测试框架搭建(七)-Ubuntu上安装配置Pycharm
  • windows 如何安装cuda pytorch gpu
  • 手动挡科目三道路驾驶技能考试及理论考试要点
  • 基于金豺优化算法python代码
  • 智慧停车怎么实现的,停车场寻车是怎么实现的
  • 网络编程初探
  • css 使用blur,实现背景色高斯模糊,但不影响背景上的内容