zoukankan      html  css  js  c++  java
  • C++17尝鲜:类模板中的模板参数自动推导

    模板参数自动推导

    在C++17之前,类模板构造器的模板参数是不能像函数模板的模板参数那样被自动推导的,比如我们无法写

    std::pair a{1, "a"s}; // C++17
    

    而只能写

    std::pair<int, string> a{1, "a"s}; // C++14
    

    为了弥补这一缺陷,标准库为我们提供了 std::make_pair 函数,通过函数模板的模板参数自动推导的功能,
    免去我们在构造 pair 时写模板参数的麻烦。

    auto a = std::make_pair(1, "a"s); // C++14
    // 相当于
    // std::pair<int, string> a = std::make_pair<int, string>(1, string("a"));
    // 这里编译器根据 std::make_pair 所带参数的类型,自动推导出了函数模板的参数。
    

    这个解决方案其实并不太理想,这是因为:

    1. 我们需要记住 make_pair, make_tuple 这类用于构造模板类的惯用法。
    2. 有些 make_XXX 函数在功能上并不等价于类模板的构造器,比如 make_shared 等等。

    在C++17中,这个问题得到了解决,类模板构造器的模板参数同样能够被自动推导

    std::pair a{1, "a"s}; // C++17
    // 相当于
    // std::pair<int, string> a{1, "a"s};
    // 和函数模板一样,这里编译器根据 std::pair 构造器所带参数类型,自动推导出了构造器模板的参数。
    

    由此我们不再需要 std::make_pair 之类的辅助函数了。

    示例

    #include <iostream>
    #include <vector>
    #include <functional>
    #include <string>
    #include <map>
    #include <algorithm>
    using namespace std;
    
    int main()
    {
        vector a = {1, 2, 3};  // C++17
    //  vector<int> a = {1, 2, 3};  // C++14
        function f = [](int a){return a + 1;};  // C++17
    //  function<int(int)> f = [](int a){return a + 1;};  // C++14
        tuple t{1, 2,5, "a"s};  // C++17
    //  tuple<int, double, string> t{1, 2,5, "a"s};  // C++14
    //  auto t = make_tuple(1, 2,5, "a"s);  // C++14
        sort(a.begin(), a.end(), greater{}); // C++17
    //  sort(a.begin(), a.end(), greater<>{});  // C++14
    //  sort(a.begin(), a.end(), greater<int>{});  // C++11
    
    //  map m = {{1, "a"s}, {2, "b"s}}; // {1, "a"s} 这种使用大括号的初始化列表没有类型
                                        // 所以编译器无法自动推导 map 类模板的参数类型
        map m = {pair{1, "a"s}, {2, "b"s}}; // C++17
    //  map<int, string> m = {{1, "a"s}, {2, "b"s}}; // C++14
    }
    

    以下内容来自视频 Class Template Argument Deduction

    自定义类模板中的应用

    template<typename T>
    struct Container
    {
        Container(T* ptr) {} // 构造器 1
        Container(T& v) {} // 构造器 2
        Container(T const& v) {} // 构造器 3
        template<typename D>
        Container(T* ptr, D& deleter) {} // 构造器 4
    };
    
    struct Deleter {};
    
    int main()
    {
        Container c{(int*)0}; // 调用构造器 1
        int x; Container c2{x}; // 调用构造器 2
        Container c3{0}; // 调用构造器 3
        Deleter d;
        Container c4{(int*)0, d}; // 调用构造器 4
    //  以上编译器自动推导的结果都是 Container<int>
    }
    

    Automatic deduction guides(自动推断向导)

    有些情况下,编译器无法对类模板的参数做出自动推导,比如下面这种模板参数类型是个嵌套类型的情况。
    此时我们需要添加自动推断向导来帮助编译器来进行自动推导。
    自动推断向导形式如下:

    类模板名(参数列表) -> 类模板id
    
    template<typename T>
    struct Traits { using type = T; };
    
    template<typename T>
    struct Container
    {
        // 参数类型是嵌套类型,无法进行自动推导
        Container(typename Traits<T>::type v) {}
    };
    
    // 自动推断向导
    template<typename T>
    Container(T) -> Container<T>;
    
    int main()
    {
        Container c(0); //  编译器自动推导的结果是 Container<int>
    }
    
  • 相关阅读:
    HDU 1698 Just a Hook(线段树区间替换)
    NBOJv2 1034 Salary Inequity(DFS序+线段树区间更新区间(最值)查询)
    NBOJv2 1004 蛤玮打扫教室(线段树区间更新区间最值查询)
    NBOJv2 1050 Just Go(线段树/树状数组区间更新单点查询)
    POJ 3468 A Simple Problem with Integers(线段树区间更新区间查询)
    HDU 1754 I Hate It(线段树单点更新区间最值查询)
    HDU 1166敌兵布阵+NOJv2 1025: Hkhv love spent money(线段树单点更新区间查询)
    GDUT——1169: Krito的讨伐(优先队列BFS)
    HDU——2444The Accomodation of Students(BFS判二分图+最大匹配裸题)
    HDU——1045Fire Net(最大匹配)
  • 原文地址:https://www.cnblogs.com/zwvista/p/7748363.html
Copyright © 2011-2022 走看看