c++primer第十六章模板特例化

c++primer第十六章模板特例化,第1张

16.5模板特例化
//第一个版本,可以比较任意两个类型
template<typename T>
int compare(const T&p1, const T&p2)
{
    cout << "太过泛型的compare版本"<<endl;

    return strcmp(p1, p2);
}


//第二个版本处理字符串字面量
template<size_t N,size_t M>
int compare(const char(&p1)[N], const char(&p2)[M])
{
    cout << "特例化的版本,能够接受字符串指针的compare" << endl;
    return strcmp(p1,p2);
}
void test01()
{
    const char* p1 = "h1", * p2 = "MOM";
    compare(p1, p2); //调用第一个模板
    compare("hi", "mom");//调用有两个非类型参数的版本

}

无法将一个指针转换为一个数组的引用,但是数组可以转换为指针,所以第二个版本是无法实例化的

定义函数模板特例化

template<>
//对比下templateint compare(const T& p1, const T& p2)的版本
//这个特例化的函数要求一个指向此类型const版本的引用
//一个指向const char 的const指针的引用
//怎么做的结果实际上就是直接帮编译器接手下面编译器本来要生成的版本
int compare(const char* const&p1, const char* const& p2)
{//const char*是针对字符串指针的,而const是针对第一个版本的const
    cout << "调用特例化的compare" << endl;
    return strcmp(p1, p2);
}

函数重载与模板特例化
compare(“hi”,“mom”)
由于是特例化版本,并不行独立的非函数模板,还是调用数组引用的版本,如果是函数,就遵行函数匹配规则

类模板·特例化
这个特例化的类模板是用来将Sales_data对象保存在无序容器中

template<class T>class std::hash;
struct Sales_data
{  
    friend class std::hash<Sales_data>;
    Sales_data() = default;
    Sales_data(const string &s):bookNO(s){ }
    Sales_data(const string &s,unsigned n,double p):bookNO(s),units_sold(n),revene(p){}
    Sales_data(istream& is)
    {
        read(is, *this);
    }


    string isbn()const { return this->bookNO; }
    Sales_data& combine(const Sales_data&rhs)
    {
  
        units_sold += rhs.units_sold;
        revene += rhs.revene;
        return *this;
    }

    double avg_price()const
    {
        if (units_sold)
        {
            return revene / units_sold;
        }
        else
        {
            return 0;
        }
    }

    istream& read(istream& is, Sales_data& item)
    {
        double price = 0;
        is >> item.bookNO >> item.units_sold >> price;
        item.revene = price * item.units_sold;

        return is;
    }

    string bookNO;
    unsigned units_sold = 0;
    double revene = 0.0;
    
};

Sales_data add(const Sales_data& lhs, const Sales_data& rhs)
{
    Sales_data sum = lhs;
    sum.combine(rhs); 
        return sum;
}

ostream& print(ostream& os, const Sales_data& item)
{
    os << item.isbn() << " " << item.units_sold << " "
        << item.revene << " " << item.avg_price();
    return os;
}


bool operator== (const Sales_data& lhs, const Sales_data& rhs)
{
    return lhs.isbn() == rhs.isbn() && lhs.units_sold == rhs.units_sold &&
        lhs.revene == rhs.revene;
}

//这下面的代码才是重点,上面只是补充Sales_data类的完整

namespace std
{
    template<>
    struct hash<Sales_data> //特例化版本 模板参数为sales_data
    {
        //用来散列一个无需容器的类型必须要定义下列类型
        typedef size_t result_type;
        typedef Sales_data argument_type; //此类型需要==

        size_t operator()(const Sales_data& s)const;
        //类使用合成的拷贝控制成员和默认构造函数
    };

    size_t hash<Sales_data>::operator()(const Sales_data& s)const
    {
        return hash<string>()(s.bookNO) ^
            hash<unsigned>()(s.units_sold) ^
            hash<double>()(s.revene);

    }
}//关闭std命名空间; 右花括号是没有分号的

int main()
{
    unordered_multiset<Sales_data>Sdest;
    
}

类模板部分特例化

//原始的。


最通用 或最泛的版本 template<class T>struct Remove_reference { typedef T type; }; //部分特例化版本,将用于左值引用和右值引用 template<class T>struct Remove_reference<T&>//左值引用 { typedef T type; }; template<class T> struct Remove_reference<T&&>//右值引用 { typedef T type; }; void test01() { int i = 0; //使用原始模板 Remove_reference<decltype(42)>::type a; //使用T&的特例化版本 Remove_reference<decltype(i)>::type b; //使用T&&的特例化版本 Remove_reference<decltype(std::move(i))>::type c; }

特例化成员而不是类

template<typename T>struct Foo
{
    Foo(const T &t =T()):mem(t){ }

    void Bar()
    { 
        cout << "使用泛的Bar()" << endl;
    }
    T mem;
};

template<> //特例化Foo模板类的成员Bar
void Foo<int>::Bar()
{
    cout << "使用特例化版本的Foo::Bar()" << endl;
}


void test02()
{
    Foo<string>fs;
    fs.Bar();
    Foo<int>fi;
    fi.Bar();
}

练习16.62

    unordered_multiset<Sales_data>Sdest;
   // test02();

    Sales_data b("abc",1,2);
    Sales_data c("vvx",2,19);
    Sdest.insert(b);
    Sdest.insert(c);


    cout << Sdest.size() << endl;
    for (auto sd : Sdest)
    {
        print(cout, sd) << endl;
    }

练习16.63 64

template<typename T>
int vec(vector<T>& vec, const T& v)
{
    int ret = 0;
    for (auto X : vec)
    {
        if (X == v)
        {
            ++ret;
        }
    }
    return ret;

}

template<>
int vec(vector<const char *>& vec,const  char *const & v)
{
    int ret = 0;
    for (auto X : vec)
    {
        if (!strcmp(X, v))
            ++ret;
    }
    return ret;
}


void test03()
{
    vector<double>a = { 1.1,2.2,3.3,4.4,5.5 };
    vector<int>b = { 1,1,1,3,4,5 };
    vector<string>c = { "1","1","2","2" };
    vector<const char*>d = {"123","sdas","ss"};
    const char* p1 = "123";
    const char* p2 = "sdas";
    const char* p3 = "ss";
    cout << vec(a, 1.1) << endl;
    cout << vec(b, 1) << endl;
    cout<<vec(c,string("2"))<<endl;
    cout<<vec(d,p1)<<endl;
}

练习16.65

template<>
string debug_rep(char* p)
{
	return debug_rep(string(p));
}
template<>
string debug_rep(const char* cp)
{
	return debug_rep(string(cp));
}

练习16.66
不希望使用通用模板版本,就自己定义类或函数的特例化版本
重载,函数匹配过程中会在重载函数中选择最佳匹配,小心设计

练习16.67
不会,特例化不会影响函数匹配,匹配规则是函数优先,
特例化版本只是接管了本来编译器应该生成版本实例化的工作
当某个模板是最佳匹配还是特殊化版本,直接略过原模板,直接使用这个模板

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/562495.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-01
下一篇 2022-04-01

发表评论

登录后才能评论

评论列表(0条)

保存