编写单一模板的时候,使之对任何可能的模板参数都是最合适的,都能实例化, 这并不总是能办到的.在某些情况下,通用模板的定义对特定类型可能是并不合适的,通用定义可能编译失败。其他时候我们也可以利用特例化来编写更加高效的代码.
特例化的本质是实例化一个模板,而不是重载它!因此特例化不影响匹配.
我们从两个方面来讨论:
1, 函数特例化.
当定义函数模板特例化的时候,我们本质上接管了编译器的工作。即,我们为原模板的一个特殊实例提供了定义。重要的是:一个特例化版本本质上是一个实例,而不是一个重载! 而且函数模板是不能部分特例化的!
#include <iostream>
template<typename Ty>
bool compare(const Ty& lh, const Ty& rh)
{
std::cout << "the base version!" << std::endl;
return (lh > rh);
}
//特例化版本
//注意下面的参数类型为什么是 const char* const&
//由于是特例化因此我们必须保持与原函数的类型匹配.
//也就是说: 我们特例化的实际上是Ty, 但是Ty前面后面的限定符号和关键字必须保存(也就是说const 和 & 必须保存)!
template<>
bool compare(const char* const& lh, const char* const& rh)
{
std::cout << "the specialized version" << std::endl;
return std::strcmp(lh, rh);
}
int main()
{
//case 1:
std::cout << std::boolalpha << compare(10, 20) << std::endl;
//case 2:
const char* str1{ "shihua" };
const char* str2{ "marryme" };
std::cout << std::boolalpha << compare(str1, str2) << std::endl;
return 0;
}
2.0, class特例化.
#include <iostream>
template<typename Ty>
class Test {
private:
Ty data;
public:
Test(const Ty& val) :data{ val } {}
Test(const Test<Ty>& other) = default;
Test(Test<Ty>&& other) = default;
Test<Ty>& operator=(const Test<Ty>& other) = default;
Test<Ty>& operator=(Test<Ty>&& other) = default;
~Test() {}
void print()const
{
std::cout << data << std::endl;
}
};
//case 1: 部分特例化.
template<>
void Test<int>::print()const
{
std::cout << "case 1" << std::endl;
}
//case 2: 部分特例化的另外一种情况.
template<typename Ty>
class Test<Ty&> {
private:
Ty data;
public:
Test(const Ty& val) :data{ val } {}
Test(const Test<Ty&>& other) = default;
Test(Test<Ty&>&& other) = default;
Test<Ty&>& operator=(const Test<Ty&>& other) = default;
Test<Ty&>& operator=(Test<Ty&>&& other) = default;
~Test() {}
void print()const
{
std::cout << "case 2" << std::endl;
}
};
//case 3: 全特例化.
template<>
class Test<char> {
private:
char data;
public:
Test(const char& val) :data{ val } {}
Test(const Test<char>& other) = default;
Test(Test<char>&& other) = default;
Test<char>& operator=(const Test<char>& other) = default;
Test<char>& operator=(Test<char>&& other) = default;
~Test() {}
void print()const
{
std::cout << "case 3"<< std::endl;
}
};
int main()
{
Test<long> t1{ 100 };
t1.print();
//case 1:
Test<int> t2{ 100 };
t2.print();
//case 2:
Test<int&> t3{ 100 };
t3.print();
//case 3:
Test<char> t4{ 'p' };
t4.print();
return 0;
}
2.1: class特例化
#include <iostream>
#include <cstdio>
#include <sstream>
template<typename Ty1>
struct Test;
template<>
struct Test<int>
{
Test(const int& value)noexcept
{
std::cout << value << std::endl;
}
};
int main()
{
Test<int> t1{ 10 };
return 0;
}
2.1.1: class特例化.
#include <iostream>
template<typename ...>
struct test;
template<>
struct test<>
{
int number_;
};
template<typename Ty1_, typename Ty2_>
struct test<Ty1_, Ty2_>
{
std::string str_;
};
int main()
{
test<> the_test_{ 20 };
test<int, bool> the_test_2{ "shihuamarryme" };
std::cout << the_test_.number_ << std::endl;
std::cout << the_test_2.str_ << std::endl;
return 0;
}