【C++】 4_C++11 新特性-語言篇

Variadic Templates

  • 談的是 templateios

    • function template
    • class template
  • 變化的是 template parameterless

    • 參數個數(variable number)ide

      • 利用參數個數遞減的特性,實現遞歸函數調用。使用 function template完成
    • 參數類型(different type)函數

      • 利用參數個數逐一遞減致使參數類型也逐一遞減的特性實現遞歸繼承或遞歸複合,以class template 完成。
void func() 
{
    /* ... */
}

template <typename T, typename ... Types>
void func(const T & firstArg, const Types &...args)
{
    // 處理 firstArg
    
    func(args...);
}

示例一

since C++11, template can have parameters that accept a variable number of template arguments. This ability is called variadic template. For example, you can use the following to call printX() for a aviable number of argument of diferent types.

(從C ++ 11開始,模板能夠具備接受可變數量的模板參數的參數。 此功能稱爲可變參數模板。 例如,你能夠使用如下代碼爲不一樣類型的大量參數調用printX()。)佈局

文件:Test.cppthis

#include <iostream>
#include <bitset>

using namespace std;

void printX()
{ }

template <typename T, typename ...Type>
void printX(const T &firstArg, const Type &...args)
{
    cout << sizeof...(args) << " "<< firstArg << endl;

    printX(args...);
}

int main()
{
    printX(7.5, "hello", bitset<16>(377), 42);

    return 0;
}

輸出:spa

3 7.5
2 hello
1 0000000101111001
0 42
If one or more arguments are passed, the function template is used, which by specifying the first argument separately allows the first argument to print and then recursively calls printX() for the remaining argument. To end the recursion, the non-template overload of printX() is provided.

(若是傳遞了一個或多個參數,則使用函數模板,經過分別指定第一個參數,能夠打印第一個參數,而後遞歸地爲其他參數調用printX()。爲告終束遞歸,提供了printX()的非模板重載。)code

示例二

使用 variadic template 重寫 printf()orm

文件:Test.cpp對象

#include <iostream>

namespace T
{

void printf(const char *s)
{
    while (*s)
    {
        if ((*s == '%') && (*(++s) != '%'))
            throw std::runtime_error("invalid format string: missing argument");

        std::cout << *s++;
    }
}

template <typename T, typename ...Args>
void printf(const char *s, T value, Args ...args)
{
    while (*s)
    {
        if ((*s == '%') && (*(++s) != '%'))
        {
            std::cout << value;

            printf(++s, args...);

            return;
        }

        std::cout << *s++;
    }

    throw std::logic_error("extra argument provided to printf");
}

}

int main()
{
    int *pi = new int{};

    T::printf("%d %s %p %f\n", 15, "This is Ace", pi, 3.1415926);

    delete pi;

    return 0;
}

示例三

文件:Test.cpp

#include <iostream>

using namespace std;

struct _Iter_less_iter
{
    template<typename _Iterator1, typename _Iterator2>

    bool operator() (_Iterator1 __it1, _Iterator2 __it2) const
    {
        return *__it1 < *__it2;
    }
};

inline _Iter_less_iter __iter_less_iter()
{
    return _Iter_less_iter();  // 臨時對象
}

template <typename _ForwardIterator, typename _Compare>
_ForwardIterator __max_element(_ForwardIterator __first,
                               _ForwardIterator __last,
                               _Compare __comp)
{
    if (__first == __last)
        return __first;

    _ForwardIterator __result = __first;

    while (++__first != __last)
        if (__comp(__result, __first))
            __result = __first;

    return __result;
}

template <typename _ForwardIterator>
inline _ForwardIterator max_element(_ForwardIterator __first,
                                    _ForwardIterator __last)
{
    return __max_element(__first, __last, __iter_less_iter());
}

template <typename _Tp>
inline _Tp max(initializer_list<_Tp> __l)
{
    return *max_element(__l.begin(), __l.end());
}

int main()
{
    cout << max({57, 48, 60, 100, 20, 18}) << endl;

    return 0;
}

若參數類型都相同,則無需使用 variadic templates, 使用 initializer_list<T> 足夠。

示例四

#include <iostream>

using namespace std;

namespace T
{

template <typename T>
T max(T value)
{
    return value;
}

template <typename T>
T max(T lh, T rh)
{
    return lh > rh ? lh : rh;
}

template <typename T, typename ...Args>
T max(T value, Args ...args)
{
    return max(value, max(args...));
}

}

int main()
{
    cout << T::max(57, 48, 60, 100, 20, 18) << endl;

    return 0;
}

示例五

  • 以異於通常的方式處理 first 元素和 last 元素

文件:Test.cpp

#include <iostream>
#include <tuple>
#include <string>
#include <bitset>

using namespace std;

template <int IDX, int MAX, typename ...Args>
struct PRINT_TUPLE
{
    static void print(std::ostream &os, const tuple<Args...> &t)
    {
        os << get<IDX>(t) << (IDX+1==MAX ? "" : ",");

        PRINT_TUPLE<IDX+1, MAX, Args...>::print(os, t);
    }
};

// 特化實現,遞歸出口
template <int MAX, typename ...Args>
struct PRINT_TUPLE <MAX, MAX, Args...>
{
    static void print(ostream &os, const tuple<Args...> &t)
    { }
};

//--------
template <typename ...Args>
ostream &operator << (ostream &os, const tuple<Args...> &t)
{
    cout << "[";
    PRINT_TUPLE<0, sizeof...(Args), Args...>::print(os, t);
    cout << "]";

    return os;
}

int main()
{
    cout << make_tuple(7.5, string("hello"), bitset<16>(377), 42) << endl;

    return 0;
}

輸出:

[7.5,hello,0000000101111001,42]

示例六

  • 用於遞歸繼承,recursive inheritance

文件:Test.cpp

#include <iostream>
#include <string>

using namespace std;

namespace T
{

// 泛型
template <typename ...Value>
class tuple;

// 特化出口
template <>
class tuple <>
{ };

// 特化
template <typename Head, typename ...Tail>
class tuple<Head, Tail...> : private tuple<Tail...>  // 私有繼承,代表兩類之間不是 ‘isa’ ,僅是內存繼承關機
{
    typedef tuple<Tail...> inherited;  // using inherited=tuple<Tail...>;

public:
    tuple()
    { }

    tuple(Head v, Tail... vtail) : inherited(vtail...), m_head(v)
    { }

    Head head()
    {
        return m_head;
    }

    inherited& tail()
    {
        return *this;
    }

protected:
    Head m_head;
};

}

int main()
{
    T::tuple<int, float, string> t(41, 6.3f, "nico");

    cout << t.head() << endl;
    cout << t.tail().head() << endl;
    cout << t.tail().tail().head() << endl;

    return 0;
}

輸出:

41
6.3
nico
  • 層析分解

1_meitu_1.jpg

  • 內存佈局

2_meitu_2.jpg

示例七

  • 用於遞歸複合,recursive composition

文件:Test.cpp

#include <iostream>
#include <string>

using namespace std;

namespace T
{

// 泛化
template <typename ...Value>
class tuple;

// 特化出口
template <>
class tuple <>
{ };

// 特化
template <typename Head, typename ...Tail>
class tuple <Head, Tail...>
{
    typedef tuple<Tail...> composited;  // using composited = tuple<Tail...>;

public:
    tuple()
    { }

    tuple(Head v, Tail... vtail) : m_tail(vtail...), m_head(v)
    { }

    Head head()
    {
        return m_head;
    }

    composited& tail()
    {
        return m_tail;
    }

protected:
    composited m_tail;
    Head m_head;
};

}

int main()
{
    T::tuple<int, float, string> t(41, 6.3f, "nico");

    cout << t.head() << endl;
    cout << t.tail().head() << endl;
    cout << t.tail().tail().head() << endl;

    return 0;
}

輸出:

41
6.3
nico
  • 遞歸調用,處理的是參數,使用 function template
  • 遞歸符合,處理的是類型,使用 class template

C++ 關鍵字

image.png

相關文章
相關標籤/搜索